Brij
Brij

Reputation: 13129

Assign value to iteration variable in C#?

I have the following code in C# utilizing foreach. In one loop I am modifying a List<T>, and in another, a string array.

We can't directly assign a value or null to the iteration variable, but we can modify its properties, and the modifications are reflected in the List finally.

So this basically means the iteration variable is a reference to the element in the list, so why we can't assign a value to it directly?

class Program
{
    public static void Main(string[] args)
    {
        List<Student> lstStudents = Student.GetStudents();

        foreach (Student st in lstStudents)
        {
            // st is modified and the modification shows in the lstStudents
            st.RollNo = st.RollNo + 1;

            // not allowed
            st = null;
        }

        string[] names = new string[] { "me", "you", "us" };

        foreach (string str in names)
        {
            // modifying str is not allowed
            str = str + "abc";
        }
    }
}

The student class:

class Student
{
    public int RollNo { get; set; }
    public string Name { get; set; }

    public static List<Student> GetStudents()
    {
        List<Student> lstStudents = new List<Student>();

        lstStudents.Add(new Student() { RollNo = 1, Name = "Me" });
        lstStudents.Add(new Student() { RollNo = 2, Name = "You" });
        lstStudents.Add(new Student() { RollNo = 3, Name = "Us" });

        return lstStudents;
    }
}

Upvotes: 3

Views: 8813

Answers (4)

Matthew Watson
Matthew Watson

Reputation: 109547

Here's a concrete example that should make it clear.

Imagine that you implement an IEnumerable<int> like so:

public static IEnumerable<int> OneToTen()
{
    for (int i = 1; i <= 10; ++i)
    {
        yield return i;
    }
}

Given that, what would it mean if in the following loop you could assign to n?

foreach (var n in OneToTen())
{
    n = 1; // Change original "collection"? There isn't one!
}

The compiler could let you change n without it having anything to do with changing the thing being iterated, but it would be misleading - which is why the compiler disallows it.

Upvotes: 1

Botz3000
Botz3000

Reputation: 39600

It's a reference type, of course you can modify its properties if they are writeable, and those changes will be reflected in the object the reference refers to.

A variable of a reference type is by definition a reference to an object. But that's something different than a reference to an actual storage location (such as a variable, or a list entry).

You can imagine it like a Student variable contains just the address where to find the original object. By copying the list entry to a variable, you are just copying the address, so now you have two addresses, once in the list and once in your variable. By reassigning the variable, you are writing another address into it, but that doesn't affect the original entry in the list. Neither does it overwrite the object that the variable referred to earlier.

That being said, foreach probably doesn't allow you to reassign the iteration variable because it could lead to confusion/bugs. The way it currently is implemented, you always know that the iteration variable is the current element.

Upvotes: 1

Roy Dictus
Roy Dictus

Reputation: 33139

This is because the compiler implements foreach with an Enumerator. Enumerators can only forward-move in a closed collection, they cannot alter the collection they iterate over.

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1062560

The iteration variable in a foreach is not a "reference to the element in the list" - it is merely the value from .Current {get;} in an iterator implementation obtained via GetEnumerator() - most commonly via IEnumerator[<T>] but not always - indeed for a List<T> it is a List<T>.Enumerator value. In the general case, there is no "meaning" to assigning to the iterator variable. Consider:

IEnumerable<int> RandomSequence(int count) {
    var rand = new Random();
    while(count-->0) yield return rand.Next();
}

This will work identically from a foreach - what would it mean to assign to it?

Thus, foreach offers no facility to assign to the iterator variable.

Upvotes: 9

Related Questions