here is the code adding data to the list, after which i return the list. Problem is that the last set of data seems to be overwriting everything else in the list
for (int k=0; k < jsonObject["mydetails"].GetArray().Count; k++)
{
//add the corresponding data from the sample array
obj.accountNumber = jsonObject["mydetails"].GetArray()[k].GetObject()["id"].GetString();
obj.accountName = jsonObject["mydetails"].GetArray()[k].GetObject()["name"].GetString();
obj.accountBall = jsonObject["mydetails"].GetArray()[k].GetObject()["age"].GetString();
mylist.Add(obj);
}
Your code isn't adding any new objects to the list, it modifies and adds the same object. In the end, the list contains X references to the same object instance.
In general it is consider bad practice to declare a variable outside the scope in which it is used. You could have avoided this problem by writing:
var myArray=jsonObject["mydetails"].GetArray();
for (int k=0; k < myArray.Count; k++)
{
var myJsonObject=myArray[k].GetObject();
var obj=new MyAccountObject();
obj.accountNumber = myJsonObject["id"].GetString();
...
}
Notice that instead of calling GetArray() and GetObject() in each line (essentially doing the job of extracting the array multiple times) I stored them in separate variables. This will result in far less CPU and memory usage.
You always add the same object obj to the list. You need to create a new in the top of the loop.
for (int k=0; k < jsonObject["mydetails"].GetArray().Count; k++)
{
obj = new ObjectType(); // you know better the type of the object you want to create.
//add the corresponding data from the sample array
obj.accountNumber = jsonObject["mydetails"].GetArray()[k].GetObject()["id"].GetString();
obj.accountName = jsonObject["mydetails"].GetArray()[k].GetObject()["name"].GetString();
obj.accountBall = jsonObject["mydetails"].GetArray()[k].GetObject()["age"].GetString();
mylist.Add(obj);
}
Without the the line obj = new ... you change the properties accountNumber, accountName and accountBall of the same object instance. At the end you add always that object reference to the list. So it seems that the last run of the loop changes all objects.
Related
I have rewritten this question because not everyone understood. Hope it's ok, it's the same main problem.Very sorry
I have a winform with 15 progress bars called: "baraClasa1", "baraClasa2", "baraClasa3" ... "baraClasa15". I have to assign the .VALUE property (as in int) to all of them, from some database records. (The records access the different values from different time periods)
I was thinking that maybe it is possible to use a loop to assign the .Value property to all of them by doing something like:
for(int i=0; i<value; i++)
{
"baraClasa+i".Value = 20 + i;
}
Is it possible to compose the name of the variables like that?
I don't know much about dictionaries, lists but looking into. If nothing works il just do the ugly:
int value = 20;
baraClasa1 = value;
baraClasa2 = value +1;....
Thank you for all help
You have to do a little reflection.
public string variable0, variable1, variable2, variable3, variable4, variable5;
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 6; i++)
{
//pretending my variable names are variable1, variable2.. ("variable" is NOT an array! just the "assign" variable)
System.Reflection.FieldInfo info = this.GetType().GetField("variable" + i.ToString());
// replace "testing" with the value you want e.g. assign[i]
info.SetValue(this, "testing");
}
// Do something with your new values
}
No need to use reflection with the updated question. The control collection has a built in find for getting a control by the name string.
for (int i = 0; i < 6; i++)
{
ProgressBar bar = (ProgressBar)this.Controls["baraClasa" + i.ToString()];
bar.Value = 50;
}
This is a design problem. Create a collection for items with common use (like progress bars for that matter) and iterate over the collection to perform actions on them.
If these are prorgress bars you might want to use an event-driven design (another link) to update their progress, meaning that each time a bar has made some progress, the event for the progress will send an update only to that bar, and not iterate over the entire list.
You may want to read an introduction to event driven programming in C# before re-factoring your code.
It really isn't possible in C# to refer to local variables in a dynamic fashion as you are trying to do. Instead what you would do in C# is store the value in a dictionary where the key can be generated in a dynamic fashion.
For example let's say all of your variable1, variable2, ... variableN were of type int. Instead of
int variable1 = 0;
int variable2 = 0;
...
int variableN = 0;
You would instead do the following
Dictionary<string, int> map = new Dictionary<string, int>();
for (int i = 0; i < N; i++) {
map[i.ToString()] = 0;
}
If the values are a of a fixed number and always linear in progress it may make sense to use an array instead of a dictionary
int[] array = new int[N];
for (int i = 0; i < N; i++) {
array[i] = 0;
}
You can't do it that way. You need an array. Every time you notice yourself having a variable2, you need an array. You may not know it yet, but you do.
No, you can't do it in C#, it's syntactically impossible. But if you want access form controls which has different names like this you can do the following:
for(int i=0; i<20; i++)
{
var name = "variable" + i;
this.Controls[name].Text = "etc..." // here you can access your control
}
If you want to have names for your objects, use a dictionary:
Dictionary<string, type> myDict = new Dictionary<string, type>()
string naming = "MyPattern{0}";
for (int i = 0; i <value; i++) {
myDict.add(string.Format(naming, i.ToString()), assign[i]);
}
And then you can access them by doing, for example:
myDict["MyPattern1"]
However, I suggest you would be better off using a collection like a List or array.
Arrays, lists, dictionaries, hash maps... collections in general are what you would use here. For example, if you have a dictionary, then it consists of key/value pairs. So a dictionary might look like this:
var variable = new Dictionary<int, string>();
Where the int is the key for any given entry, and the string is the value. You'd assign values in something like this:
for(int i = 0; i < value; i++)
variable.Add(i, assign[i]);
Of course, since i is just an incrementing integer in this case (unless you have some other key in mind?), then it works just as well as an indexer on a list. Something like this:
var variable = new List<string>();
for (int i = 0; i < value; i++)
variable.Add(assign[i]);
In both cases, you'd access the assigned value later by referencing its key (in a dictionary) or its index (in a list, or any array):
var someOtherVariable = variable[x];
Where x is an integer value present in the dictionary's keys or in the array's size.
If you can put names of all variables in an array such as 'variable', and they are unique, you can try to use dictionary :
Dictionary<object, object> dictionary = new Dictionary<string, object>();
for(int i=0; i<value; i++)
{
dictionary.Add(variable[i], assign[i]);
}
bgList.Add(bg1);
bgList.Add(bg2);
bgList.Add(bg3);
bgList.Add(bg4);
bgList.Add(bg5);
//Initialize all background objects
for (int i = 0; i < bgList.Count; i++)
{
bgList[i] = new Sprite();
bgList[i].Scale = 2.0f;
}
Is this a legitimate way to do this? Basically, the question boils down to "Can I initialize a list of objects using a for loop?
I'm getting "This Object will never not be null" warnings on the bg1, bg2, bg3, bg4, and bg5 objects, and that's making me wonder if this technique isn't allowed.
These statements are not equivalent:
bg1 = new Sprite();
and
bgList.Add(bg1);
bgList[0] = new Sprite();
The latter will not assign the reference to the new instance to bg1. It just stores the new instance in the 0th location.
So using a collection and loop to instantiate a number of variables is not a working short-cut. You have to instantiate each variable explicitly, or use an array or collection from the first place.
a foreach would be easier for sure, and y you should be able to do it, but imo you can also add the items in the loop something like.
for (int i = 0; i < bgList.Count; i++)
{
var bglistitem = new Sprite()
bhlistitem.Scale = 2.0f;
bgList.Add(bglistitem);
}
I have a list of objects and I'm doing a foreach on the list and I'm sending each object to a method that modifies the object and returns it; like this:
foreach (MyObjectModel o in TheMasterObject.ListOfMyObjectModel)
{
o = MyMethod(o);
}
That doesn't work. What I want to do is replace the object I'm iterating on with the modified version that gets returned by MyMethod.
What do I need to change?
Thanks.
You cannot reassign to the loop variable, and reassigning the variable wouldn't affect the object inside the list anyway. If you need to write over the object in a list, use a for loop.
for (int index = 0; index < list.Count; index++)
{
var obj = list[index];
list[index] = MyMethod(obj);
}
You cannot do it like this. C# does not allow modifying the iteration variable of the foreach. Your best option is to hold a secondary list and put the modified values in there and then replace the initial list. Alternatively, if your data structure allows direct indexing, you can replace the foreach with a for and then you will be able to assign the object directly.
If MyObjectModel is a class (not a struct) then you don't need to reassign it. A class is a reference type which means your method will get a pointer to the object in the collection. Any modifications you do in the method will be done on the actual object in the list. You don't need to replace it.
If it's a completely new object you are returning, then do what Anthony Pegram is suggesting.
for (int i =0; i < TheMasterObject.ListOfMyObjectModel.size(); ++i) {
TheMasterObject.ListOfMyObjectModel.set(i, MyMethod(TheMasterObject.ListOfMyObjectModel.get(i)));
}
I wrote this with java thinking, if some changes need to let it work on C#, be my guest
Use a for-loop instead of an iterator.
for (int i = 0; i < objectModels.Count; i++) {
objectModels[i] = MyMethod(objectModels[i]);
}
As for the why, this questions explains it:
Why is the iteration variable readonly
Hope this helps
Y
I've got a bit of code that I've been working on for a friend for the past few days. At a high level it parses a text file and writes to an MDB. To cut a long story short, I've got a nested couple of loops doing some processing on the items. The inner loop only gets called in certain cases, but when it does, it's doing some strange things.
ArrayList CaseRecordItems = new ArrayList(); // this is created earlier
string baseTif = "sometext_"; // this is created earlier
CaseRecord cr = new CaseRecord(); (this gets populated with "stuff")
char increment = 'A';
for (int i = 0; i < FirstNames.Count; i++)
{
cr.Firstname = (string)FirstNames[i];
cr.Lastname = (string)LastNames[i];
if (FirstNames.Count > 1)
{
cr.Tif = baseTif + increment.ToString();
increment++;
}
CaseRecordItems.Add(cr);
}
The loop runs for example two times and should set the value of cr.Tif to sometext_A and sometext_B. This works correctly, but once the second item is added to the collection, the value of the first is changed to match it.
I suspect this is due to a lack of my understanding how these objects are being instantiated and passed around. Any insight would be appreciated.
EDIT:
Based on the awesome feedback (and my numb-nutzery) the issue has been resolved. Thanks to Dan's answer I made a couple of changes to the code that I had tried before utilizing the clone function (yes, beach I had actually tried that :P).
The new block looks like this:
ArrayList CaseRecordItems = new ArrayList(); // this is created earlier
string baseTif = "sometext_"; // this is created earlier
CaseRecord cr = new CaseRecord(); // this gets populated with "stuff")
char increment = 'A';
for (int i = 0; i < FirstNames.Count; i++)
{
CaseRecord cr2 = new CaseRecord();
cr2 = cr.Clone(); // preserves the data from outside
cr2.Firstname = (string)FirstNames[i];
cr2.Lastname = (string)LastNames[i];
if (FirstNames.Count > 1)
{
cr2.Tif = baseTif + increment.ToString();
increment++;
}
CaseRecordItems.Add(cr2);
}
Thanks everyone for the super-quick responses!
I assume cr is an object. You're not creating a new cr each time, and so you have the same reference in the arraylist twice, thus when you modify it the second time you're actually working on the same object.
You are changing the value of the cr instance inside the loop. Each iteration through the loop is using the same instance of cr so when you change it, they all change. To resolve this, an appropriate method is to use a local instance inside the loop:
for (int i = 0; i < FirstNames.Count; i++)
{
CaseRecord cr=new CaseRecord();
...
CaseRecordItems.Add(cr);
}
The problem is that the variable cr is the same both times through the loop, so both times through the loop the same object is being modified and the same object is getting added to the ArrayList twice.
You don't show enough of the code to show where cr is declared.
Do you need to do something like
for (int i = 0; i < FirstNames.Count; i++)
{
CRObject cr = new CRObject();
cr.Firstname = (string)FirstNames[i];
cr.Lastname = (string)LastNames[i];
if (FirstNames.Count > 1)
{
cr.Tif = baseTif + increment.ToString();
increment++;
}
CaseRecordItems.Add(cr);
}
Does the cr object have a clone function?
If so, this should do it:
CaseRecordItems.Add(cr.Clone());
Since cr is not getting a new statement (I dont' know cr's type or I would show you), you are just adding the same reference over and over. If you want to add new cr items to CaseRecordItems you new to do a cr = new TypeOfCR(); otherwise you are just overwriting the same object over and over.
EDIT: Be sure to do the new inside of your loop
If you're not creating cr (whatever it is) inside the for loop, then you're modifying the same object, over and over, each time through the loop. You want to create a new cr instance inside the for loop.
Assuming cr is a class, you will need to create a new instance of the class on each pass through the loop, like cr = new crClassName();
The reason is that what is being added to CaseRecordItems is a pointer to the object, not a copy of it - which is why when you change it on the second pass the first value appears to change also.
for (int z = 0; z < alParmValues.Count; z++)
{
//string[] def;
string[] asd = alParmValues[z].ToString().Split(',');//this is of type string.collections and u cant cast it to a arraylist or array
//if (HUTT.clsParameterValues.bCustomObj == false)
string[] def = alMethSign[z].ToString().Substring(alMethSign[z].ToString().IndexOf('(') + 1, alMethSign[z].ToString().IndexOf(')') - (alMethSign[z].ToString().IndexOf('(') + 1)).Split(',');
}
I have to access both the string arrays outside the loop. Is there a better solution to this? I can't use an ArrayList or declare them as public so how can I access them?
To access something outside of a loop, just declare it outside of the loop, then work with it after your loop processing is done:
string[] arr = ...
for (int z = 0; z < alParmValues.Count; z++)
{
// work with arr...
}
var item = arr[3]; // Accessed outside of loop.
However, there seem to be a few things wrong with your code. I'd recommend thinking a little bit more about the loop body and what you're trying to do there. Consider this line, for example:
for (int z = 0; z < alParmValues.Count; z++)
{
// ...
string[] asd = alParmValues[z].ToString().Split(',');
// There aren't any more references to asd after this point in the loop,
// so this assignment serves no purpose and only keeps its last assigned
// value.
}
This assignment is pointless; every time you go through the loop, you just overwrite the previous value of asd, and you never use it later in the loop.
The scope of both asd and def are limited to the body of the for loop. If you have to access them you need to declare them outside the loop. Is there a problem in putting them out?
Take a look at the Collection Classes Tutorial on MSDN.
Both 'asd' and 'def' are string arrays whose scope is limited to the for loop. You cannot access them outside the loop. If you want to do so, try declaring them outside the for loop.
First, if you want access to the data extracted/computed inside the loop, you must declare a container for the results outside the loop, and then populate its values inside the loop.
Second, don't think about casting the arrays returned from the split method, but rather think about processing their contents.
Assuming that you want the combined results from all elements of the original alParmValues array in a single pair of results, I'd use something like the following pseudo-code. Of course, you'll need to fill in the type for your alParmValues and alMethSign elements, add semicolons, etc. (Because your question didn't explain the content and relationships between the two arrays being processed in your loop, I've just treated them independently.) This isn't complete code, but just a sketch to get you started:
ArrayList allValues = new ArrayList()
foreach (??? parameter in alParmValues) {
foreach (String value in parameter.ToString().Split(',')) {
allValues.add(value)
}
}
ArrayList allMethSignValues = new ArrayList()
foreach (??? methSign in alMethSign) {
String thisString = methSign.toString()
int open = thisString.indexOf('(')
int close = thisString.indexOf(')')
String parenPart = thisString.substring(open + 1, close - open - 1)
foreach (String value in parenPart.split(',')) {
allMethSignValues.add(value)
}
}