-1

Case 1 - I have a list of string, say

List<string> source = new List<string>();`
source.Add("one");
source.Add("two");
source.Add("three");

If i update the value for "two" using below code, it wont update the value.

Example -

source.ForEach(x => {if (x == "two"){x = "twenty";}});

Case 2 - But when I have a List<ComplexObject> obj = new List<ComplexObject>() with two property Key, DisplayText with value as

1,"One"
2, "two"

And I try to update using below code, the value will be updated

 obj.ForEach(x => {if (x.Key == 2){ x.DisplayText = "Update value for 2";}});

Though both are list but why is the behaviour different?

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • 4
    Does this answer your question? [Why can't we assign a foreach iteration variable, whereas we can completely modify it with an accessor?](https://stackoverflow.com/questions/7838079/why-cant-we-assign-a-foreach-iteration-variable-whereas-we-can-completely-modi) Also, most people don't use `.ForEach` the method, it's better to use an actual foreach loop or a Linq method that doesn't cause side effects (such a Select) – gunr2171 Aug 24 '22 at 18:20
  • I'm looking for an appropriate duplicate, but the difference is that in one case you are only assigning to a local variable and in the other case you are mutating a property on an object. It has nothing to do with being a list or being a string. If you update your "working" example to do the same thing as the "not working" example (set a new value to `x` rather than update a property on `x`) then you'll observe the same "not working" behavior. In short... The behavior is different because *your tests* are different. – David Aug 24 '22 at 18:21
  • 1
    The two versions are not equivalent. Try `obj.ForEach(x => {if (x.Key == 2){ x = new ComplexObject { DisplayText = "Update value for 2"}; }});` – Raymond Chen Aug 24 '22 at 18:31

1 Answers1

1

This problem refers to understanding how parameters works and what is delegate.

The "thing" you pass in ForEach method is function, which has parameter, so it called Action delegate. This mean, that this is simple function with one single parameter. So you need to remember, that "x"(your param name inside ForEach) is not exactly item, that placed inside your list, this is parameter, which have the same behavior with simple parameter of function.

In first case: string, as we know is reference type, but it has value type behavor, so you get no change of source value, because new variable created and chars inside string copied to chars of new variable.

In second case: classes` objects in C# have references to their fileds in heap, so when item of your list proces inside ForEach and pass object like parameter, ComplexObject' object copy all the references to new object. So it's also whole new variable, but references to fields remains the same

ForEach and various methods, which accept delegate works like simple loop with passing each item to this function(it's obviosly much complex, but for general understanding it`s ok).

Red Star
  • 556
  • 3
  • 13
  • 1
    IMHO what you are saying is correct, BUT it’s not well explained for a - so I assume - beginner – Rand Random Aug 24 '22 at 18:34
  • 1
    @RandRandom, I made some... minor changes, i think that okay now – Red Star Aug 24 '22 at 19:05
  • Thanks for the answer. So but when i am executing the below source of code, why does it update the value, despite here string also as a reference type. SO why does the below code works perfectly for (int i = 0; i < source.Count; i++) { if (source[i]== "two") source[i] = "twenty"; } I am just trying to get my basics clear. – ForAssistance Aug 24 '22 at 19:07
  • @ForAssistance, In C# string is unique class, because it have the same behavior as struct, that happend because they are immutable,. When you pass string to method, you won't see behavior like with simple classes object, you won`t receive changed variable (if you not using return). In case, that you wrote it works as you expected, because you don't pass them as parameter and you changing local variable. You need to learn about immurtable – Red Star Aug 24 '22 at 19:13
  • @RedStar: The example in that comment has nothing to do with immutability or with strings being "special". That example works for the exact same reason the second case in the original question works. Because the code is *mutating a value* instead of *assigning a variable*. Variable re-assignment only matters locally to the variable's scope, and makes no changes to whatever value or object was previously referenced by that variable. Updating an element in an array is mutating that array. – David Aug 25 '22 at 11:36