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

前端 未结 9 482
情歌与酒
情歌与酒 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 09:03

    It would be possible to make item mutable. We could change the way the code is produced so that:

    foreach (var item in MyObjectList)
    {
      item = Value;
    }
    

    Became equivalent to:

    using(var enumerator = MyObjectList.GetEnumerator())
    {
      while(enumerator.MoveNext())
      {
        var item = enumerator.Current;
        item = Value;
      }
    }
    

    And it would then compile. It would not however affect the collection.

    And there's the rub. The code:

    foreach (var item in MyObjectList)
    {
      item = Value;
    }
    

    Has two reasonable ways for a human to think about it. One is that item is just a place-holder and changing it is no different to changing item in:

    for(int item = 0; item < 100; item++)
        item *= 2; //perfectly valid
    

    The other is that changing item would actually change the collection.

    In the former case, we can just assign item to another variable, and then play with that, so there's no loss. In the latter case this is both prohibited (or at least, you can't expect to alter a collection while iterating through it, though it doesn't have to be enforced by all enumerators) and in many cases impossible to provide (depending on the nature of the enumerable).

    Even if we considered the former case to be the "correct" implementation, the fact that it could be reasonably interpreted by humans in two different ways is a good enough reason to avoid allowing it, especially considering we can easily work around that in any case.

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

    foreach is a read only iterator that iterates dynamically classes that implement IEnumerable, each cycle in foreach will call the IEnumerable to get the next item, the item you have is a read only reference, you can not re-assign it, but simply calling item.Value is accessing it and assigning some value to a read/write attribute yet still the reference of item a read only reference.

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

    Because the first one doesn't make much sense, basically. The variable item is controlled by the iterator (set on each iteration). You shouldn't need to change it- just use another variable:

    foreach (var item in MyObjectList)
    {
        var someOtherItem = Value;
    
        ....
    }
    

    As for the second, there are valid use cases there- you might want to iterate over an enumeration of cars and call .Drive() on each one, or set car.gasTank = full;

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