views:

144

answers:

5
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 explainations 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

+13  A: 

You're using them as mutable structs. Avoid doing that:

http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil

Or we'll unleash the Skeet on you.

Joel Etherton
+6  A: 

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.

Rohith
+5  A: 

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.

burkestar
+1  A: 

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.

Vinay B R
A: 

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 of ms (though it still won't do what you might expect).

Jeff Sternal
then why can I do modify them in Quick Watch? Nevermind, that also works on a copy of the struct, ugh why do structs even exist?
Nico
@Nico: Structs have a purpose, but *mutable* structs almost never do.
Adam Robinson
@Nico: All you're doing is modifying a copy that then gets thrown away. It's essentially a no-op.
Steven Sudit