Please refer the below code
List<ProductDM> productDMList = _orderRepo.GetProductList(32, 12);
for (int i=0;i<productDMList.Count;i++)
{
productDMList[i].CabinetList[i].Min = productDMList[i].Min;
productDMList[i].CabinetList[i].Max = productDMList[i].Max;
}
public class ProductDM
{
public List<InventoryDM> CabinetList { get; set; }
public double Min { get; set; }
public double Max { get; set; }
}
public class InventoryDM
{
public Double Min { get; set; }
public Double Max { get; set; }
}
The requirement is to loop through the productDMList and bind the returned MIN and MAX values inside the cabinet list. ProductDM fills with MIN and MAX amounts but when assigning those to CabinetList, it returns an error.
This is because the CabinetList is initially empty and it doesn't show the MIN MAX properties in it.
I am using the above code to assign data but returns
Object reference not set to an instance of an object.
because of the CabinetList empty.
How to initialize the cabinet list here???
As Marco Forberg's answer states initializing the CabinetList in the constructor prevents the
Object reference not set to an instance of an object.
exception.
In addition to this, instead of assigning the Min and Max values via the index accessor:
productDMList[i].CabinetList[i].Min = productDMList[i].Min;
productDMList[i].CabinetList[i].Max = productDMList[i].Max;
You should use the Add() method of the List<> type:
productDMList[i].CabinetList.Add(new InventoryDM { Min = productDMList[i].Min, Max = productDMList[i].Max });
otherwise you will get an
ArgumentOutOfRangeException
because you try to access an item on the list which doesn't exist yet.
Depending on your requirements you could do something like this
public class ProductDM
{
public List<InventoryDM> CabinetList { get; private set; }
public double Min { get; set; }
public double Max { get; set; }
public ProductDM()
{
CabinetList = new List<InventoryDM>();
}
}
or if you get your CabinetList data from an external source, e.g. database:
public class ProductDM
{
private List<InventoryDM> _cabinetList = null;
public double Min { get; set; }
public double Max { get; set; }
public List<InventoryDM> CabinetList
{ get
{
if(_cabinetList == null)
{
_cabinetList = ... // retrieve data from external source
}
return _cabinetList;
}
}
}
The issue is not the emptiness of the CabinetList, instead the list of objects is null as you can see in the debugger.
In order to initialize the list you can refer to the answers of this post:
How to initialize a C# string list (List<string>) with many string values
Note that you don't have a list of string but a list of <InventoryBM> objects, but the concept is analogous.
Related
This question is related to this question. I managed to get one step further, but I am now unable to initialize my whole object with default values in order to prevent it from being null at list level. The goal of this is to hand down the "null" values to my SQL query. Ultimately what I want is one record in my DB that will express: This row has been recorded, but the related values were "null".
I have tried Brian's fiddle and it does not seem to work for me to initialize the whole model with standard values.
Expectation: Upon object initialisation the "null" values should be used and then overwritten in case there is a value coming through JSON deserialisation.
Here is what I have tried. None of this will have the desired effect. I receive this error:
Application_Error: System.ArgumentNullException: Value cannot be null.
Every time I try to access one of the lists in the data model.
namespace Project.MyJob
{
public class JsonModel
{
public JsonModel()
{
Type_X type_x = new Type_X(); // This works fine.
List<Actions> action = new List<Actions>(); // This is never visible
/*in my object either before I initialise JObject or after. So whatever
gets initialised here never makes it to my object. Only Type_X appears
to be working as expected. */
action.Add(new Actions {number = "null", time = "null", station =
"null", unitState = "null"}) // This also does not prevent my
//JsonModel object from being null.
}
public string objectNumber { get; set; }
public string objectFamily { get; set; }
public string objectOrder { get; set; }
public string location { get; set; }
public string place { get; set; }
public string inventionTime { get; set; }
public string lastUpdate { get; set; }
public string condition { get; set; }
public Type_X Type_X { get; set; }
public List<Actions> actions { get; set; }
}
public class Actions
{
public Actions()
{
// None of this seems to play a role at inititialisation.
count = "null";
datetime = "null";
place = "null";
status = "null";
}
// public string count { get; set; } = "null"; should be the same as above
// but also does not do anything.
public string count { get; set; }
public string datetime { get; set; }
public string place { get; set; }
public string status { get; set; }
}
public class Type_X
{
public Type_X
{
partA = "null"; // This works.
}
public string partA { get; set; }
public string PartB { get; set; }
public string partC { get; set; }
public string partD { get; set; }
public string partE { get; set; }
}
}
This is how I now initialize the object based on Brian's answer.
JObject = JsonConvert.DeserializeObject< JsonModel >(json.ToString(), new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore});
When I try to iterate over Actions' content, it (logically) gives me above mentioned null error.
for (int i = 0, len = JObject.actions.Count(); i < len; i++)
My current understanding of constructor initialisations:
If I define values such as count = "null"; they should appear in any new object that is created.
If default values are present I would then also expect that a list that has items with default values (such as count for ex.) would be of Count() 1 and not null. How is that even possible?
This will get you out of your bind:
private List<Actions> _actions = new List<Actions>();
public List<Actions> actions { get => _actions; set => _actions = value ?? _actions; }
This causes trying to set actions to null to set it to the previous value, and it is initially not null so it can never be null.
I'm not absolutely sure I'm reading your question right, so here's the same fragment for partA:
private string _partA = "null";
public string partA { get => _partA; set => _partA = value ?? _partA; }
I have found that in some cases, initializing generic lists with their default constructor on your model increases ease of use. Otherwise you will always want to validate they are not null before applying any logic(even something as simple as checking list length). Especially if the entity is being hydrated outside of user code, i.e. database, webapi, etc...
One option is to break up your initialization into two parts. Part 1 being the basic initialization via default constructor, and part 2 being the rest of your hydration logic:
JObject = new List < YourModel >();
... < deserialization code here >
Alternatively you could do this in your deserialization code, but it would add a bit of complexity. Following this approach will allow you to clean up your code in other areas since each access will not need to be immediately proceeded by a null check.
My Main problem is : if i add "N" group to company and check it in the last , i see all of "Man"s arrange into all of groups like together ?
i this my problem is in the definition of class or references .
This is my code :
public class Man
{
public int Code { get; set; }
public string Name { get; set; }
public int Priority { get; set; }
public int Stoptime { get; set; }
public Boolean Lunch { get; set; }
public DateTime Arrival { get; set; }
public DateTime Departure { get; set; }
public int LunchTime { get; set; }
}
public class Group
{
public List<Man> People { get; set; }
public double Speed { get; set; }
public double Rate { get; set; }
public double Surcharge { get; set; }
public double TotalRate { get; set; }
}
public class Company
{
public List<Group> Groups { get; set; }
public Group BestGroup { get; set; }
public double Rate { get; set; }
public double Surcharge { get; set; }
public double FullRate { get; set; }
}
private List<Man> ShufflePosts(List<Man> ShufflePeoples)
{
List<Man> Temp = ShufflePeoples;
List<Man> Commixed = new List<Man>();
Random rand = new Random();
do
{
int shf = rand.Next(0, Temp.Count);
Commixed.Add(Temp[shf]);
Temp.RemoveAt(shf);
} while (Temp.Count > 1);
Commixed.Add(Temp[0]);
return Commixed;
}
public void CAStart(List<Man> Peoples)
{
var _Race = new Company();
_Race.Groups = new List<Group>();
for (int i = 0; i < 5; i++)
{
var Gr = new Group();
Gr.People = ShufflePosts(Peoples);
_Race.Groups.Add(Gr);
}
}
In the code Commixed.Add(Temp[0]); VS show me error index out of range.
I check the variable and see below data:
ShufflePeoples.Count = 0, Temp.Count = 0, Commixed.Count = 1
Why this happens ?
Where is my problem ?
Why you get the error:
Your do while loop runs until Temp.Count > 1 isn't true - which will happen when you removed all items from it with line Temp.RemoveAt(shf);.
Then you try accessing Temp[0] (the first item) but temp is empty and you get an index out of range error.
Try to change your loop's condition and avoid accessing a specific position in the collection without checking that that position exists. Or better still use a simple while instead and then you won't need to specially address the last item in Temp
A nice solution for shuffling:
var suffled = ShufflePeoples.OrderBy(item => Guid.NewGuid());
Change your loop to avoid index out of range error:
while (Temp.Count > 0)
{
int shf = rand.Next(0, Temp.Count);
Commixed.Add(Temp[shf]);
Temp.RemoveAt(shf);
};
When you remove item from Temp, you also remove it from ShufflePeoples because you refer Temp = ShufflePeoples, to avoid it, just make new list then copy items from ShufflePeoples to Temp.
You remove all Temp items in do-while loop, so when you try to access Temp[0] after loop, it will give you index out of range.
For the first time, ShufflePosts method will remove all the contents of the ShufflePeoples.
Therefore the second time you run ShufflePosts method, ShufflePeoples or Temp' is basically empty, which means if you try to accessTemp[0]`, it will give you index out of range Exception.
My 2 cents:
Avoid assigning Temp = ShufflePeoples, instead do Copy Constructor Temp = new List<Man>(ShufflePeoples), to make sure that you do not adjust the parameter accidentally
Always check your initial condition of your parameter argument.
I have a c# object 'Product' with a property called: Offset
In the database the field is of type nvarchar(50)
I will be storing a JSON value in it such as the following: { "y": 0, "m": 0, "d": 0 }
I would like to know a good way of working with a property like this in my code. Here is how I currently am doing it:
public class Product
{
public int Id {get; set;}
public string Description {get; set;}
public decimal Price {get; set;}
public int OffsetYears { get; set; }
public int OffsetMonths { get; set; }
public int OffsetDays { get; set; }
public string Offset
{
get
{
Offset offset = new Offset()
{
Y = OffsetYears,
M = OffsetMonths,
D = OffsetDays
};
return JsonConvert.SerializeObject(offset);
}
set
{
OffsetObj offset = JsonConvert.DeserializeObject<Offset>(value);
OffsetYears = offset.Y;
OffsetMonths = offset.M;
OffsetDays = offset.D;
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
So then when I accept values from the User in the UI I would set the OffsetYears, OffsetMonths, and OffsetDays properties.. So in my repository I can just save Offset.
And when retrieving values from the database I will simply work with OffsetYears, OffsetMonths, and OffsetDays properties in my code.
Is there a better way to handle this sort of thing? I just feel like I am not utilizing all of my c# resources. Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
Or am I better off just creating 3 separate integer fields in the database and avoiding all of this...
I would hold the values in a field of your private type. Consider this approach:
public class Product
{
private OffsetObj _offset = new OffsetObj();
public int Id { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int OffsetYears
{
get { return _offset.Y; }
set { _offset.Y = value; }
}
public int OffsetMonths
{
get { return _offset.M; }
set { _offset.M = value; }
}
public int OffsetDays
{
get { return _offset.D; }
set { _offset.D = value; }
}
public string Offset
{
get
{
return JsonConvert.SerializeObject(_offset);
}
set
{
_offset = JsonConvert.DeserializeObject<OffsetObj>(value);
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
This way, the field offset will hold the values for the offset.
Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
JsonConvert will throw a JsonReaderException if trying to set the Offset property to a string that does not match JSON-format. In my opinion this is expected. To clarify further, you could name your property to OffsetJson.
However, I fail to see the benefit in this simple case to store your information as JSON. If you are using a relational database, you may as well just store your values in separate columns.
I have the following class:
class Channel
{
public int Number { get; private set; }
public double HighestCoChannelSignal { get; private set; }
public double HighestOverlappingSignal { get; private set; }
public List<Network> NetsCoChannel { get; set; }
public List<Network> NetsOverlapping { get; set; }
}
I have a list of Channel objects. I want to bind it to a DataGridView and show: Number, HighestCoChannelSignal, HighestOverlappingSignal, NetsCoChannel.Count, NetsOverlapping.Count. And for example if the HighestCoChannelSignal is a special value set the cell value in DataGridView to something I want. How can I achieve this?
You can perform a LINQ query to get the data you want into instances of an anonymous type and bind the result to the grid, e.g.
var data = channels.Select(c => new {c.Number,
c.HighestCoChannelSignal,
c.HighestOverlappingSignal,
NetsCoChannelCount = c.NetsCoChannel.Count,
NetsOverlappingCount = c.NetsOverlapping.Count})
.ToArray();
You can add whatever code is appropriate to deal with that "special value". If you want a specific answer then you'll have to provide a specific description.
I need to set a default value to a member class, this value can vary and it's set at the beginning of the execution; I have this so far, minScore is my default value
public class Zones : GeneralIndicator
{
public int IndicatorType { get; set; }
public string Code { get; set; }
public string Score { get; set; } //TODO: calcular desde aca el score usando el indicatortype
public double Latitude { get; set; }
public double Longitude { get; set; }
private int minScore = 0;
public void setMinScore(int value)
{
minScore = value;
}
}
I get the minScore value as a parameter when calling the application. What's the best way to set minScore for every object generated in runtime?
Two options:
Create a ZonesFactory class, which takes a defaultMinScore in the constructor (to remember) and has a CreateZones method which creates an instance and sets the min score:
public class ZonesFactory
{
private readonly int defaultMinScore;
public ZonesFactory(int defaultMinScore)
{
this.defaultMinScore = defaultMinScore;
}
public Zones CreateZones()
{
return new Zones(defaultMinScore);
}
}
Note that here I'm assuming you also create a new constructor for Zones which takes the minScore as a parameter. I suggest you get rid of the setMinScore method (which violates .NET naming conventions apart from anything else).
Use a static variable to keep the default, and set it in the Zones constructor
Personally I'd prefer the first of these.