[ACCEPTED]-Why is The Iteration Variable in a C# foreach statement read-only?-language-design
Lets start out with a silly but illustrative 29 example:
Object o = 15;
o = "apples";
At no point do we get the impression 28 that we just turned the number 15 into a 27 string of apples. We know that o
is simply 26 a pointer. Now lets do this in iterator 25 form.
int[] nums = { 15, 16, 17 };
foreach (Object o in nums) {
o = "apples";
}
Again, this really accomplishes nothing. Or 24 at least it would accomplish nothing were it 23 to compile. It certainly wouldn't insert 22 our string into the int array -- that's 21 not allowed, and we know that o
is just a 20 pointer anyway.
Let's take your example:
foreach (Position Location in Map)
{
//We want to fudge the position to hide the exact coordinates
Location = Location + Random(); //Compiler Error
Plot(Location);
}
Were 19 this to compile, the Location
in your example stars 18 out referring to a value in Map
, but then you 17 change it to refer to a new Position
(implicitly 16 created by the addition operator). Functionally 15 it's equivalent to this (which DOES compile):
foreach (Position Location in Map)
{
//We want to fudge the position to hide the exact coordinates
Position Location2 = Location + Random(); //No more Error
Plot(Location2);
}
So, why 14 does Microsoft prohibit you from re-assigning 13 the pointer used for iteration? Clarity 12 for one thing -- you don't want people assigning 11 to it thinking they've changed your position 10 within the loop. Ease of implementation 9 for another: The variable might hide some 8 internal logic indicating the state of the 7 loop in progress.
But more importantly, there 6 is no reason for you to want to assign to it. It 5 represents the current element of the looping 4 sequence. Assigning a value to it breaks 3 the "Single Responsibility Principle" or 2 Curly's Law if you follow Coding Horror. A variable 1 should mean one thing only.
If the variable were mutable, that might 5 give an incorrect impression. For example:
string[] names = { "Jon", "Holly", "Tom", "Robin", "William" };
foreach (string name in names)
{
name = name + " Skeet";
}
Some 4 people might think that would change the array 3 contents. It's reaching a bit, but it might 2 be a reason. I'll look it up in my annotated 1 spec tonight...
I think its artificial limitation, no really 7 need to do it. To prove the point, take 6 this code into considiration, and a possible 5 solution to your problem. The problem is 4 to asign, but internal changes of objects 3 don't present a problem:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<MyObject> colection =new List<MyObject>{ new MyObject{ id=1, Name="obj1" },
new MyObject{ id=2, Name="obj2"} };
foreach (MyObject b in colection)
{
// b += 3; //Doesn't work
b.Add(3); //Works
}
}
class MyObject
{
public static MyObject operator +(MyObject b1, int b2)
{
return new MyObject { id = b1.id + b2, Name = b1.Name };
}
public void Add(int b2)
{
this.id += b2;
}
public string Name;
public int id;
}
}
}
I didn't know about 2 this phenomena, because I was always modifying 1 the objects the way I described.
When you modify the collection, the modification 5 might have unpredictable side effects. The 4 enumerator has no way of knowing how to 3 deal correctly with these side effects, so 2 they made the collections immutable.
See 1 also this question: What is the best way to modify a list in a foreach
The foreach statement works with Enumerable. The 11 thing that is different with an Enumerable 10 is that it doesn't know about the collection 9 as a whole, it's almost blind.
This means 8 that it doesn't know what's coming next, or 7 indeed if there is anything until the next 6 iteration cycle. That why there you see 5 .ToList() a lot so people can grab a count 4 of the Enumerable.
For some reason that I'm 3 not sure about, this means that you need 2 to ensure your collection isn't changing 1 as you try to move the enumerator along.
The condition to work with IEnumerable objects 11 is that the underlying collection must not 10 change while you are accessing it with Enumerable. You 9 can presume that the Enumerable object is 8 a snap shot of the original collection. So 7 if you tries to change the collection while 6 enumerating it'll throw an exception. However 5 the fetched objects in Enumeration is not 4 immutable at all.
Since the variable used 3 in foreach loop is local to the loop block 2 this variable is however not available outside 1 the block.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.