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
Related
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.
I'm wanting to turn off multiple game objects and all their associated children at once with a single method call.
My thinking behind this was to create a list to hold all of the game objects I want to deactivate and pass all those objects in. However, I'm trying to implement the actual SetActive method call with my list and Im running into some issues.
Here is my code just now:
public List<GameObject> deactivate_Screen = new List<GameObject>();
void OnClick()
{
for( int i = 0; i < deactivate_Screen.Count; i++)
{
deactivate_Screen.SetActive(false);
}
}
Now the obvious reason this isn't working is clear to me. A list can't access to the SetActive function I'm trying to achieve. However, I'm at a loss to implement the functionality I require.
Could someone please show me what I need to do, or point me in the right direction to fix my error?
As you correctly recognized, SetActive is a method of a GameObject, not of the List<GameObject>.
You have to invoke SetActive in each iteration for the game object the index i of the current iteration refers to - you can access that object with the List<T> indexer, i.e. by placing square brackets with the index behind deactivate_Screen.
Thus, the "current item" in each iteration is deactivate_Screen[i], hence your loop should look as follows:
for (int i = 0; i < deactivate_Screen.Count; i++)
{
deactivate_Screen[i].SetActive(false);
}
Just replace
deactivate_Screen.SetActive(false);
to
deactivate_Screen[i].SetActive(false);
As List itself is not a game object but its elements are List[0] List[1] List[2] List[3].....
In your loop you need to access the element of the list at the index i:
for( int i = 0; i < deactivate_Screen.Count; i++)
{
deactivate_Screen[i].SetActive(false);
}
or using a foreach loop
foreach (var gobj in deactivate_Screen)
{
gobj.SetActive(false);
}
I have a List<T> and I need to avoid the behavior I'm about to outline:
// assume cls and numberToAdd are parameters passed in.
int pos = numberToAdd;
List<MyClass> objs = new List<MyClass>(numberToAdd);
for(int i = 0; i < numberToAdd; i++)
{
objs.Add(cls);
objs[i].X = -((pos * cls.Width) + cls.Width / 2);
pos--;
}
Console.WriteLine(objs[0].X + "\r\n" + objs[1].X);
This results in this writeline printing the same value.
Basically what I need is to change the behavior of the "Add" method. I'd like to add a new instance of the object with the same values and not simply a reference to the same object. I understand this will use alot more memory.
What is the 'cls' variable? Just create a new one inside each loop. What you want to do is clone it; but honestly that'll be confusing. I'd suggest just creating a new one per loop.
-- Edit
Noticed you'd comment about 'cls'.
I suggest you clone it then (assuming you can't change the call and do my above suggestion). Do this by just creating a new one, and copying all the properties over.
Typically, if you have control of the Type of 'cls', you just make a 'Copy' constructor. It's like so:
class Foo {
private int x;
public Foo (Foo toCopy) {
this.x = toCopy.x;
}
...
}
Might want to extend cls to include a clone method. Extension method would work if you can't modify the cls class.
then change
objs.Add(cls);
to
objs.Add(cls.Clone());
Ah. You need to implement cls as a struct so that it exhibits pass by value semantics.
OR you need to implement a clone method on your cls object so that you can create a method to clone the object and thus create a new reference to it so that you can do this.
Even if you don't have access to the object itself you may be able to create an extension method to do this.
public cls Clone(this cls)
{
//initialise the object to clone it.
return new cls(this.param1, this.param2,...)
}
Looks like the same object, cls is getting added numberToAdd times to the list.
You need to create a new instance of your objects inside the loop.
for(int i = 0; i < numberToAdd; i++)
{
MyClass c=new MyClass(...);
c.X = -((pos * c.Width) + c.Width / 2);
objs.Add(c);
pos--;
}
Have MyClass Implement ICloneable and then simply use
objs.Add((MyClass)cls.Clone());
If I declared a dictionary like this:
private static Dictionary<string, object> aDict = new Dictionary<string, object>();
And now I want to use it at another place. How do I reset it?
aDict = new Dictionary<string, object>(); // like this?
aDict = null; // or like this?
or other reset styles?
You can simply use the Clear method, it will remove all keys and values, then you can reuse it without having to create new instances:
aDict.Clear();
Try this
aDict.Clear();
aDict.Clear(); will work.
aDict.Clear(); is the only way to go since you don't want to change the reference and keep the same object available at another place
As everybody has pretty much answered that .Clear() method provided on the Dictionary class should be the way to go here (can't agree more).
Just to make it clear (for newbies of course ;)) that why not the other approaches, like creating a new instance every time we need to refresh the dictionary
aDict = new Dictionary<string, object>(); // like this?
because even though this way works, it is not a memory efficient approach as this creates a new instance and leaves behind the old instance(s) of the dictionary waiting for GC (garbage collector) to dispose it (as it is no longer referred). So you would agree on not consuming extra memory when you don't need to :)
and
aDict = null; // or like this?
because this leaves your instance set to null and next time as the OP wanted to use it as a dict, OP has to create another instance (yes, you got it right not memory efficient)
and also this won't be a better programming style here as someone might end up doing .ContainsKey() (or any operation on the dictionary for that matter)on the aDict variable and cause a nullPointerException if aDict is still pointing to a null object.
Hope this explanation helps!! Thanks for reading!
Running a decompile of the Clear method in Resharper on a Dictionary object shows this:
/// <summary>Removes all keys and values from the <see cref="T:System.Collections.Generic.Dictionary`2" />.</summary>
[__DynamicallyInvokable]
public void Clear()
{
if (this.count <= 0)
return;
for (int index = 0; index < this.buckets.Length; ++index)
this.buckets[index] = -1;
Array.Clear((Array) this.entries, 0, this.count);
this.freeList = -1;
this.count = 0;
this.freeCount = 0;
++this.version;
}
The dictionary contains an integer array of buckets and other control variables that are either set to -1 or 0 to effectively clear the keys and values from the dictionary object. It is pretty many variables representing a valid state of the Dictionary as we can see in the .NET source code. Interesting.
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)
}
}