Why is foreach loop Read-Only in C#
Asked Answered
Q

3

16

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;
}
Quincey answered 23/10, 2010 at 15:42 Comment(5)
I think he's talking about the iteration variable, as in foreach ( Item theItem in theItemList )... theItem cannot be assigned to.Interlude
Check out #776930Shrill
Yes I am saying about foreach loop. Naturally it's a loop right? In for loop we can iterate through an array and change the value in the array same time but foreach doesn't work.Quincey
@Zai: well, not true strictly speaking; see my answer below.Towage
What I think is even more interesting is that you also can't add or remove from the collection from within the foreach.Ciracirca
A
12

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

Acne answered 23/10, 2010 at 15:46 Comment(1)
When you say // This could modify the object in the original collection, that would be only if the collection was not a pure IEnumerable, ie a Collection or a List, right?Tsunami
G
9

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 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
Gelatinate answered 23/10, 2010 at 15:50 Comment(3)
"And modifying the copy is useless." What if I want to do something like sum the square of all the numbers in a list? It can be done with the read-only restriction, but it's often useful to modify a copy.Split
+1 for "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." Finally an answer that explains it thoroughly.Tsunami
But if you can update a property on the object that is referred to by the iteration variable, couldn't this also change the ordering in an ordered list?Tsunami
T
0

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.

Towage answered 23/10, 2010 at 15:50 Comment(3)
Actually, you cannot modify a field/property of the object refered to by the variable of iteration, either.Acne
@Michael: The code I posted works OK for me. I am using .NET 3.5 and Visual Studio 2008.Towage
@MichaelGoldshteyn only the iteration variable is read only, not the object is refers to.Tsunami

© 2022 - 2024 — McMap. All rights reserved.