Does foreach() iterate by reference?

C#ReferenceForeach

C# Problem Overview


Consider this:

List<MyClass> obj_list = get_the_list();
foreach( MyClass obj in obj_list )
{
    obj.property = 42;
}

Is obj a reference to the corresponding object within the list so that when I change the property the change will persist in the object instance once constructed somewhere?

C# Solutions


Solution 1 - C#

Yes, obj is a reference to the current object in the collection (assuming MyClass is in fact a class). If you change any properties via the reference, you're changing the object, just like you would expect.

Be aware however, that you cannot change the variable obj itself as it is the iteration variable. You'll get a compile error if you try. That means that you can't null it and if you're iterating value types, you can't modify any members as that would be changing the value.

The C# language specification states (8.8.4)

> "The iteration variable corresponds to > a read-only local variable with a > scope that extends over the embedded > statement."

Solution 2 - C#

Yes, until you change the generic type from List to IEnumerable..

Solution 3 - C#

You've asked 2 different questions here, lets take them in order.

Does a foreach loop iterate by reference?

If you mean in the same sense as a C++ for loop by reference, then no. C# does not have local variable references in the same sense as C++ and hence doesn't support this type of iteration.

Will the change be persisted

Assuming that MyClass is a reference type, the answer is yes. A class is a reference type in .Net and hence the iteration variable is a reference to the one variable, not a copy. This would not be true for a value type.

Solution 4 - C#

Well, it happened to me that my changes were not updated in a foreach loop when I iterated through var collection:

var players = this.GetAllPlayers();
foreach (Player player in players)
{
    player.Position = 1;
}

When I changed var to List it started working.

Solution 5 - C#

You can in this instance (using a List<T>) but if you were to be iterating over the generic IEnumerable<T> then it becomes dependant on its implementation.

If it was still a List<T> or T[] for instance, all would work as expected. The big gotcha comes when you are working with an IEnumerable<T> that was constructed using yield. In this case, you can no longer modify properties of T within an iteration and expect them to be present if you iterate the same IEnumerable<T> again.

Solution 6 - C#

Maybe it's interesting for you to lean that by version C# 7.3 it's possible to change values by reference provided that the enumerator's Current property returns a reference Type. The following would be valid (verbatim copy from the MS docs):

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}

Read more about this new feature at [C# foreach statement | Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in "C# foreach statement | Microsoft Docs").

Solution 7 - C#

this is true as long as it is not a struct.

Solution 8 - C#

Well, without understanding exactly what you mean by "Iterate by reference", I can't answer specifically yes or no, but I can say that what's going on under the surface is that the .net framework is constructing an "enumerator" class for each time client code calls a foreach, for the life of the foreach, that maintains a reference pointer into the collection being iterated over, and each time your foreach iterates, ir "delivers" one item and "increments" the pointer or reference in the enumerator to the next item...

This happens regardless of whether the items in the collection you are iterating over are values types or reference types.

Solution 9 - C#

obj is a reference to an item inside the List, hence if you change it's value it will persist. Now what you should be concerned about is whether or not get_the_list(); is making a deep copy of the List or returning the same instance.

Solution 10 - C#

Yes, that's also why you cannot alter the enumerable object in the context of the foreach statement.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsharkinView Question on Stackoverflow
Solution 1 - C#Brian RasmussenView Answer on Stackoverflow
Solution 2 - C#jaccsoView Answer on Stackoverflow
Solution 3 - C#JaredParView Answer on Stackoverflow
Solution 4 - C#mrzepaView Answer on Stackoverflow
Solution 5 - C#J KeeganView Answer on Stackoverflow
Solution 6 - C#WolfView Answer on Stackoverflow
Solution 7 - C#DeepfreezedView Answer on Stackoverflow
Solution 8 - C#Charles BretanaView Answer on Stackoverflow
Solution 9 - C#Stan R.View Answer on Stackoverflow
Solution 10 - C#Brian ScottView Answer on Stackoverflow