简体   繁体   中英

Why is foreach loop Read-Only in C#

Why is foreach loop a read only? I mean you can fetch the data but can't increase++ or decrease--. Any reason behind it? Yes I am a beginner :)

Exmaple:

int[] myArray={1,2,3};
foreach (int num in myArray)
{
  num+=1;
}

That is because foreach is meant to iterate over a container, making sure each item is visited exactly once, without changing the container, to avoid nasty side effects.

See: foreach in MSDN

If you meant why would changes to an element like an integer not affect a container of integers, well this is because the variable of iteration in this case would be a value type and is copied, eg:

// Warning: Does not compile
foreach (int i in ints)
{
  ++i; // Would not change the int in ints
}

Even if the variable of iteration was a reference type, whose operations returned a new object, you wouldn't be changing the original collection, you would just be reassigning to this variable most of the time:

// Warning: Does not compile
foreach (MyClass ob in objs)
{
  ob=ob+ob; // Reassigning to local ob, not changing the one from the original 
            // collection of objs
}

The following example has the potential to actually modify the object in the original collection by calling a mutating method:

// Warning: Does not compile
foreach (MyClass ob in objs)
{
  ob.ChangeMe(); // This could modify the object in the original collection
}

To avoid confusion with regard to value vs reference types and the scenarios mentioned above (along with some reasons related to optimization), MS chose to make the variable of iteration readonly .

Because the current element is returned by value(ie copied). And modifying the copy is useless. If it is a reference type you can modify the content of that object, but can't replace the reference.

Perhaps you should read the documentation of IEnumerable<T> and IEnumerator<T> . That should make it clearer. The most important bit is that IEnumerable<T> has a property Current of type T . And this property has only a getter, but no setter.

But what would happen if it had a setter?

  • It would work well with arrays and Lists
  • It wouldn't work well with complex containers like hashtables, ordered list because the change causes larger changes in the container(for example a reordering), and thus invalidates the iterator. (Most collections invalidate the iterators if they get modified to avoid inconsistent state in the iterators.)
  • In LINQ it does make no sense at all. For example with select(x=>f(x)) the values are results of a function and have no permanent storage associated.
  • With iterators written with the yield return syntax it doesn't make sense either

foreach is designed to visit each item in a collection exactly once, and does not use an explicit "loop index"; if you want more control over the loop and have a loop index, use for .

EDIT: You can change the items in the collection being iterated on inside a foreach loop. For example:

foreach(Chair ch in mychairs)
{
    ch.PaintColour = Colour.Green; //this alters the chair object *in* the collection.
}

You cannot, however, add or remove items to/from the collection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM