ForEach will not alter/change items in list C#

﹥>﹥吖頭↗ 提交于 2021-02-04 15:08:45

问题


I'm pretty sure this has worked before in some code I have written, not sure what I am missing here.

The following code does not change the string values in my list. Why?

var items = listBox1.Items.Cast<string>().ToList();
items.ForEach(item => item = (!chkBox1.Checked) ? "move " + item : "move -check " + item);

EDIT : Just to clarify, the list remains the same as when it was created.

EDIT : Apologies, the items list (listBox1.Items) contains alphanumeric strings as follows.

J00123456

J00123344

J00123458

Also, just to confirm, I have successfully done this with a custom list of T (shown below), which is why I thought it would work here.

var tapes = new List<TapeInfo>();
... //Populated list
tapes.ForEach(x => x.vItem = "tapelib 3592 -eject " + x.vItem);  //Works here

回答1:


You should use the Select function if you want to get a different result.

var items = listBox1.Items.Cast<string>().ToList();
listBox1.Items = items.Select(item => (!chkBox1.Checked) ? "move " + item : "move -check " + item).ToList();

The ForEach function can do something according to a collection value, but can't do it to the values themselves.

The Select function will create a new collection according to the given collection.

Edit

About your edit of successfully changing values by using

tapes.ForEach(x => x.vItem = "tapelib 3592 -eject " + x.vItem);

You need to understand how passing argument by value/reference works.

In c#, when writing var obj1 = new object(), obj1 is a pointer to the new object() that exists on the heap.

When you pass obj1 to a function public void Foo(object obj) { //... } by calling Foo(obj1), the function will get the parameter as new pointer to the same object on the heap.

Therefore, when you use ForeEach on the object itself,

object.ForEach(obj => obj = new object()) // No changed outside the Foreach

only the new pointer will be changed and it will point on a new object but the original pointer isn't changed.

But if you use it on an inner object,

object.ForEach(obj => obj.InnerObject = new object()) // Changed outside the Foreach

this will change the pointed inner object and the inner object will be changed.




回答2:


strings are immutable, so they cannot be changed. Assigning another value to that variable only changes that variable (difference between call-by-reference and call-by-value).

When you use the ForEach-method, you actually iterate over your items-list using the item-variable declared in your lambda-expression. Assigning a different value to that variable, cannot change the list.

And to have it clear what my first sentence means: You cannot change the value of your variable, because it's immutable, so you assign the variable, which cannot take affect to the list.




回答3:


Foreach simply can't do it, since item is a local variable within the loop's scope.
What you have is basically the same as using the long version:

foreach(string item in listBox1.Items.Cast<string>().ToList())
{
    item = (!chkBox1.Checked) ? "move " + item : "move -check " + item;
}

you can use a for loop to achieve your goal:

string Item;
for(var i=0;i < listBox1.Items.Count; i++)
{
    Item = listBox1.Items[i].ToString(); // Listbox Items are objects, so you need to use ToString() here
    listBox1.Items[i] = (chkBox1.Checked) ? "move -check " + Item : "move " + Item;
}

That's assuming, of course, that the items are and should be strings. I've also improved readability of your ternary condition.



来源:https://stackoverflow.com/questions/29911734/foreach-will-not-alter-change-items-in-list-c-sharp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!