Why can't we assign a foreach iteration variable, whereas we can completely modify it with an accessor?

前端 未结 9 481
情歌与酒
情歌与酒 2020-11-28 08:13

I was just curious about this: the following code will not compile, because we cannot modify a foreach iteration variable:

        foreach (var item in MyObj         


        
相关标签:
9条回答
  • 2020-11-28 08:51

    Use for loop instead of foreach loop and assign value. it will work

    foreach (var a in FixValue)
    {
        for (int i = 0; i < str.Count(); i++)
        {
           if (a.Value.Contains(str[i]))
               str[i] = a.Key;
        }
     }
    
    0 讨论(0)
  • 2020-11-28 08:57

    The second isn't doing the same thing at all. It's not changing the value of the item variable - it's changing a property of the object to which that value refers. These two would only be equivalent if item is a mutable value type - in which case you should change that anyway, as mutable value types are evil. (They behave in all kinds of ways which the unwary developer may not expect.)

    It's the same as this:

    private readonly StringBuilder builder = new StringBuilder();
    
    // Later...
    builder = null; // Not allowed - you can't change the *variable*
    
    // Allowed - changes the contents of the *object* to which the value
    // of builder refers.
    builder.Append("Foo");
    

    See my article on references and values for more information.

    0 讨论(0)
  • 2020-11-28 08:57

    Because the two are not the same. When doing the first, you might expect to change the value that is in the collection. But the way foreach works, there is no way that could have been done. It can only retrieve items from the collection, not set them.

    But once you have the item, it's an object like any other and you can modify it in any (allowed) way you can.

    0 讨论(0)
  • 2020-11-28 08:59

    If you look at the language specification you can see why this is not working:

    The specs say that a foreach is expanded to the following code:

     E e = ((C)(x)).GetEnumerator();
       try {
          V v;
          while (e.MoveNext()) {
             v = (V)(T)e.Current;
                      embedded-statement
          }
       }
       finally {
          … // Dispose e
       }
    

    As you can see the current element is used to call MoveNext() one. So if you change the current element the code is 'lost' and can't iterate over the collection. So changing the element to something else doesn't make any sense if you see what code the compiler is actually producing.

    0 讨论(0)
  • 2020-11-28 09:00

    You can't modify a collection while it's being enumerated. The second example only updates a property of the object, which is entirely different.

    Use a for loop if you need to add/remove/modify elements in a collection:

    for (int i = 0; i < MyObjectList.Count; i++)
    {
        MyObjectList[i] = new MyObject();
    }
    
    0 讨论(0)
  • 2020-11-28 09:01

    The point is that you cannot modify the collection itself while iterating over it. It is absolutely legal and common to modify the objects the iterator yields.

    0 讨论(0)
提交回复
热议问题