Why are assignment operators (=) invalid in a foreach
loop? 开发者_开发知识库 I'm using C#, but I would assume that the argument is the same for other languages that support foreach
(e.g. PHP). For example, if I do something like this:
string[] sArray = new string[5];
foreach (string item in sArray)
{
item = "Some assignment.\r\n";
}
I get an error, "Cannot assign to 'item' because it is a 'foreach iteration variable'."
Here's your code:
foreach (string item in sArray)
{
item = "Some assignment.\r\n";
}
Here's a rough approximation of what the compiler does with this:
using (var enumerator = sArray.GetEnumerator())
{
string item;
while (enumerator.MoveNext())
{
item = enumerator.Current;
// Your code gets put here
}
}
The IEnumerator<T>.Current
property is read-only, but that's not actually relevant here, as you are attempting to assign the local item
variable to a new value. The compile-time check preventing you from doing so is in place basically to protect you from doing something that isn't going to work like you expect (i.e., changing a local variable and having no effect on the underlying collection/sequence).
If you want to modify the internals of an indexed collection such as a string[]
while enumerating, the traditional way is to use a for
loop instead of a foreach
:
for (int i = 0; i < sArray.Length; ++i)
{
sArray[i] = "Some assignment.\r\n";
}
Because the language specification says so.
But seriously, not all sequences are arrays or things that can be logically modified or written to. For instance:
foreach (var i in Enumerable.Range(1, 100)) {
// modification of `i` will not make much sense here.
}
While it would've been technically possible to have i = something;
modify a local variable, it can be misleading (you may think it really changes something under the hood and it wouldn't be the case).
To support these kind of sequences, IEnumerable<T>
doesn't require a set
accessor for its Current
property, making it read-only. Thus, foreach
cannot modify the underlying collection (if one exists) using the Current
property.
The foreach
loop is designed to iterate through objects in a collection, not to assign things- it's simply design of the language.
Also, from MSDN:
"This error occurs when an assignment to variable occurs in a read- only context. Read-only contexts include foreach iteration variables, using variables, and fixed variables. To resolve this error, avoid assignments to a statement variable in using blocks, foreach statements, and fixed statements."
The foreach keyword just enumerates IEnumerable instances (getting an IEnumerator instances by calling the GetEnumerator() method). IEnumerator is read-only, therefore values can't be changed using IEnumerator =can't be changed using the foreach context.
Because you can't use a foreach
loop to modify an array you're looping through. The loop iterates through the array, so if you try to modify what it's iterating through then unexpected behavior may occur. Furthermore, as Darin and DMan have pointed out, you're iterating through an IEnumerable
which is itself read-only.
PHP makes a copy of the array in its foreach
loop and iterates through that copy, unless you use references, in which case you'll modify the array itself.
Because an IEnumerable
is readonly.
In general, if you're trying to do this, you need to think long and hard about your design, because you're probably not using the best construction. In this case, the best answer would probably be
string[] sArray = Enumerable.Repeat("Some assignment.\r\n", 5).ToArray();
Higher level constructions are almost always usable instead of this kind of loop in C#. (And C++, but that's a whole other topic)
You cannot modify an array that you are foreach'ing through. Use The following code instead:
string[] sArray = new string[5];
for (int i=0;i<sArray.Length;i++)
{
item[i] = "Some Assignment.\r\n";
}
The foreach is designed to interate through the array once, without repeating or skipping (though you can skip some action within the foreach construct by using the continue keyword). If you want to modify the current item, consider using a for loop instead.
You cannot modify a list that is being looped through via a "ForEach".
The best option is to simply create a temporary list to store the items you wish to use.
It would be perfectly possible to let it be altered. However, what does this then mean? It would read like the underlying enumeration was modified, which it isn't (it would be possible to allow that too, but that has its own downsides).
So you'd have code that people would naturally read as indicating something other than what has actually happened. Considering that the purpose of a computer language is primarily to be understood by people (compilers deal with the balance being set against them, unless you use assembly, machine code, or the appropriately named Brainf**k) this would indicate a flaw in the language.
精彩评论