Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are assignment operators (=) invalid in a foreach loop?

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'."

like image 471
Jim Fell Avatar asked Aug 23 '10 16:08

Jim Fell


3 Answers

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";
}
like image 190
Dan Tao Avatar answered Oct 22 '22 22:10

Dan Tao


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.

like image 6
mmx Avatar answered Oct 22 '22 23:10

mmx


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.

like image 5
Dominic K Avatar answered Oct 22 '22 23:10

Dominic K