在C#中Foreach结构奇怪的编译错误

时间:2010-09-24 19:15:37

标签: c# generics compiler-construction struct foreach

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;
        }
    }
}

对此有任何合理的解释吗?

编译器返回:

  

错误:       无法修改'ms'的成员,因为它是'foreach迭代   变量'

修改

额外问题:

我刚刚尝试更改MyFunction中的字符串,但实际上并未更新ms。但是:如果我去快速监视并在那里分配相同的值,它会更新ms。如果它首先不应该编译,为什么会发生这种情况,不应该快速计划抛出异常?

EDIT2:

好的,快速观看也适用于ms的副本,这就是为什么我可以编辑它的值,它实际上并没有改变MyPrivateVariable的内容。

5 个答案:

答案 0 :(得分:14)

你将它们用作可变结构。避免这样做:

Why are mutable structs “evil”?

答案 1 :(得分:6)

Struct具有值类型语义。因此,对struct实例所做的任何修改都不会影响原始实例。 C#编译器试图警告你这个。

答案 2 :(得分:5)

C#不会在“foreach(MyStruct ms ...)”中通过引用迭代结构,因此该上下文中的ms是不可变的。

用类替换MyStruct。

QuickWatch可以操作堆栈上的值类型。

答案 3 :(得分:1)

这是因为struct是valuetype而不是引用类型。如果MyStruct是一个类,它将编译没有问题。检查this主题以获取详细信息。

答案 4 :(得分:0)

您无法更改迭代变量引用的内容:也就是说,您无法将变量指向其他实例(要查明原因,请参阅Why is The Iteration Variable in a C# foreach statement read-only?)。

'修改'结构(值类型)会创建类型的新实例,因此语句ms.MyBool = false毫无意义。

MyFunction(ms)的调用进行编译,因为它在ms副本上运行(尽管它仍然无法达到您的预期效果)。