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

namespace MyNamespace { public struct MyStruct { public string MyString; public int MyInt; public bool MyBool; } public class MyClass { private List MyPrivateVariable; public List MyVariable { get { if (MyPrivateVariable == null) { MyPrivateVariable = new List(); 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 iteration variable’

编辑:

额外的问题:

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

EDIT2:

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

你正在使用它们作为可变结构。 避免这样做:

为什么可变结构“邪恶”?

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

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

用类替换MyStruct。

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

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

您无法更改迭代变量引用的内容:也就是说,您无法将变量指向另一个实例(要找出原因,请参阅为什么C#foreach语句中的迭代变量是只读的? )。

‘修改’结构(值类型)会创建该类型的新实例 ,因此语句ms.MyBool = false是没有意义的。

MyFunction(ms)的调用编译是因为它在ms 的副本上运行(尽管它仍然不会按照您的预期执行)。