tags:

views:

158

answers:

4

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;
}
+4  A: 

That is because foreach is meant to iterate over a container, making sure each item is visited exactly one, 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, e.g.:

// 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 original collection
}

Now something like this could modify the object in the original collection:

// 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.

Michael Goldshteyn
A: 

Read this Readonly Foreach .

anivas
+1  A: 

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.

CesarGon
Actually, you cannot modify a field/property of the object refered to by the variable of iteration, either.
Michael Goldshteyn
@Michael: The code I posted works OK for me. I am using .NET 3.5 and Visual Studio 2008.
CesarGon
+4  A: 

Because the current element is returned by value(i.e. 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 bis 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
CodeInChaos