namespace MyNamespace
{
public struct MyStruct
{
public string MyString;
public int MyInt;
public bool MyBool;
}
public class MyClass
{
private List<MyStruct> MyPrivateVariable;
public List<MyStruct> MyVariable
{
get
{
if (MyPrivateVariable == null)
{
MyPrivateVariable = new List<MyStruct>();
MyPrivateVariable.Add(new MyStruct());
MyPrivateVariable.Add(new MyStruct());
}
return MyPrivateVariable;
}
}
public void MyLoop()
{
foreach (MyStruct ms in MyVariable)
{
// Doesn't compile, but it works if you execute it through the Immediate window, or in Quickwatch
ms.MyBool = false;
// Compiles, works
MyFunction(ms);
}
}
public void MyFunction(MyStruct ms)
{
ms.MyBool = false;
}
}
}
Any reasonable explanations for this?
The compiler returns:
Error: Cannot modify members of 'ms' because it is 'foreach iteration variable'
EDIT:
Extra question:
I just tried changing a string from MyFunction
, and it doesn't actually update ms
. BUT: If I go to quickwatch and assign the same value there, it does update ms
. Why does this happen if it shouldn't even be compiling in the first place, shouldn't quickwatch throw an exception?
EDIT2:
Ok, quick watch also works on a copy of ms
, so that's why I can edit it's value, it doesn't actually alter the contents of MyPrivateVariable
.
Struct has value type semantics. So any modification you make to the struct instance wouldn't affect the original instance. The C# compiler is trying to warn you of this.
C# doesn't iterate structs by reference in the "foreach (MyStruct ms...)" so ms in that context is immutable.
Replace MyStruct with a class instead.
QuickWatch can manipulate value types on the stack.
this is because struct is valuetype and not a reference type. if MyStruct was a class it would have compiled without issues. check this thread for details.
You can't change what an iteration variable references: that is, you can't point the variable to a different instance (to find out why that is, see Why is The Iteration Variable in a C# foreach statement read-only?).
'Modifying' a struct (a value type) creates a new instance of the type, so the statement
ms.MyBool = false
is meaningless.The call to
MyFunction(ms)
compiles because it operates on a copy ofms
(though it still won't do what you might expect).You're using them as mutable structs. Avoid doing that:
Why are mutable structs “evil”?