I have the following code:
newsplit.ToList().ForEach(x => x = "WW");
I would expect that all elements in the list are now "WW" but they are still the original value. How come? What do I have to do different?
Assuming that newsplit
is an IEnumerable<string>
, you want:
newsplit = newsplit.Select(x => "WW");
The code that you currently have is equivalent to the following:
foreach(string x in newsplit.ToList()) {
AssignmentAction(x);
}
...
public static void AssignmentAction(string x) {
x = "WW";
}
This method won't modify x
because of the pass-by-value semantics of C# and the immutability of strings.
Other answers have explained why your current code doesn't work. Here's an extension method which would fix it:
// Must be in a static non-nested class
public static void ModifyEach<T>(this IList<T> source,
Func<T,T> projection)
{
for (int i = 0; i < source.Count; i++)
{
source[i] = projection(source[i]);
}
}
Then use like this:
newsplit.ModifyEach(x => "WW");
That will work with any implementation of IList<T>
such as arrays and List<T>
. If you need it to work with an arbitrary IEnumerable<T>
then you've got a problem, as the sequence itself may not be mutable.
Using Select()
is a more functional approach of course, but sometimes mutating an existing collection is worth doing...
The ForEach will allow you to manipulate the elements of the IEnumerable, but not change the reference of the element.
ie, this would set a Foo
property of each element in the IEnumerable to the string "WW"
:
newsplit.ToList().ForEach(x => x.Foo = "WW");
However, you won't be able to modify the values inside the IEnumerable itself.
It's because the LINQ expression is creating Anonymous Types, and these are read-only. They can't be assigned to. Also, in a standard for each loop you cannot assign to a collection that is being enumerated. Try:
foreach (var item in newsplit)
{
item = "this won't work";
}