Member-only story
Foreach and IEnumerable
I’ve been reading a lot about foreach
and the iterator pattern lately.
During my research, I came up with these questions:
- How is the foreach iteration variable readonly?
- Why does the compiler allow the assignment of the iteration variable when using the iterator pattern directly?
- Why is
IEnumerator.Current
readonly? - Why can’t I add/remove elements in an
IEnumerable<T>
? - Why does the runtime allow you to update a property of an element in an
IEnumerable<T>
? - Why is
IEnumerable<T>
necessary when there isIEnumerator<T>
? - When is
Array.GetEnumerator()
used?
This page will go into these questions and the answers I got from StackOverflow.
How is the foreach iteration variable readonly?
Why?
Answering “why” is easy, because it stops you from thinking that you’d be updating the element in the collection, which you wouldn’t, because you’re dealing with a local variable that just has a reference to the element in the collection.
Updating the reference in a local variable doesn’t do anything to the object in the collection.
How?
The “how” was a bit more difficult to find out.
In 8.8.4 of the C# specification, it provides this example:
A foreach statement of the form:
foreach (V v in x) embedded-statement
is then expanded to:
{
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}
The iteration variable corresponds to a read-only local variable with a scope that extends over the embedded statement. The variable v is read-only in the embedded statement.
I was confused as to how this was possible when the “expanded” code doesn’t have any readonly keywords.
The expanded code is the C# equivalent of the CIL code that is generated.