warrens
warrens

Reputation: 2115

Can a foreach iteration variable not change for ANY reason?

I have a foreach statement with an iteration variable named "rcnesw".

foreach( RCNESW rcnesw in shiftersave )
{
    TestG.ShiftQuad( rcQuads, rcnesw.row, rcnesw.col, GO_.Up);

    // other code...
}

During debugging the values of rcnesw.row and rcnesw.col CHANGE as a result of the call to ShiftQuad -- I thought the foreach loop variable was readonly. Is it ever not readonly?

Note: the TestG.ShiftQuad method also has a foreach loop in it with its own local (I thought local) variable which has the very same name and type: RCNESW rcnesw. That value seems to transmit back up to the calling foreach location.

(=====edit=====adding=====)

First, thanks to all for the info on the "mutable" nature of the "readonly" variable. That clarifies the situation (that the C#/.NET docs do not).

Further info on the ShiftQuad method, it is:

public void ShiftQuad( List<RCPair> rcList, int row, int col, int dir )

And inside that method nothing changes row or col. ShiftQuad declares its own rcnesw:

RCNESW rcnesw = null;

Or does it? Does that statement not create a new instance of RCNESW? Because when that method makes rcnesw.row and rcnesw.col change then the calling method receives those changes apparently.

public class RCNESW
{
    public int row;
    public int col;
    public bool bNorth;
    public bool bEast;
    public bool bSouth;
    public bool bWest;
}

At this point I still think it is a compiler bug. Changes to a local variable should not emerge at the caller through variables that are called by value.

(====edit====solved===) This issue was really related not to local vs non-local (or pass by value), the screwup was in how some lists became aliases for the same objects.

Upvotes: 4

Views: 972

Answers (3)

Jeppe Stig Nielsen
Jeppe Stig Nielsen

Reputation: 61952

In the body of the loop

foreach( RCNESW rcnesw in shiftersave )

the loop variable rcnesw is read-only, but exactly what that means depends heavily on whether RCNESW is a reference type (class type, interface type, delegate type, array type) or a value type (struct type, enum type).

If RCNESW is a reference type, the only thing that can't be mutated is the value of rcnesw which is the reference. So the "identity" of which object is being referred by rcnesw can't change. However, the state of that same object may change dramatically; there is no limitation there.

Upvotes: 2

Szymon
Szymon

Reputation: 43023

You can obviously change the object properties of the object that is referred to by each iteration of the foreach loop.

You should not change the collection though. Citing MSDN:

The foreach statement is used to iterate through the collection to get the information that you want, but can not be used to add or remove items from the source collection to avoid unpredictable side effects. If you need to add or remove items from the source collection, use a for loop.

Upvotes: 1

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239674

Whenever you encounter read only concepts in C#, it's almost always a shallow form of read only - you can't change which object the variable is referring to, but you can make changes to that object's own properties (or call methods on it, etc)

The same applies for readonly fields of a class - you can't change the reference but you can mutate the object.

Upvotes: 8

Related Questions