C中的foreach struct怪异编译错误#

问题描述:

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

对此有何合理的解释?C中的foreach struct怪异编译错误#

编译器回报:

Error: Cannot modify members of 'ms' because it is 'foreach iteration variable'

编辑:

额外的问题:

我只是想从MyFunction改变一个字符串,它实际上并没有更新ms。但是:如果我去quickwatch并在那里分配相同的值,它会更新ms。为什么会发生这种情况,如果它不应该编译在第一位,不应该quickwatch抛出异常?

EDIT2:

好,见效快的手表也适用于的ms副本,所以这就是为什么我可以修改它的价值,它实际上并没有改变的MyPrivateVariable内容。

+0

什么是编译器错误? – 2010-09-24 19:18:51

+0

编译器消息说什么? – CodingGorilla 2010-09-24 19:19:01

+0

什么是编译器错误信息? – EJC 2010-09-24 19:19:02

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

Why are mutable structs “evil”?

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

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

用类代替MyStruct。

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

+0

有时候在一个简单的暴露字段'Holder '类中包装一个可变结构对于在某些情况下使用是有用的,但仅仅用一个可变类替换一个可变结构以促进集合中事物的变异是一个坏主意。一般来说,每个可变对象应该只有一个封装其可变状态的其他对象。如果想从一个List >复制到另一个List中的某个地方,那么List2 [1] .Value = List1 [3] .Value;'。要追加一个列表项到另一个列表中,说'List2.Add(new Holder (List1 [3]))''。 – supercat 2012-09-17 23:56:40

这是因为结构是valuetype而不是引用类型。如果MyStruct是一个没有问题编译的类。详情请查询this线程。

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

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

MyFunction(ms)调用编译,因为它副本ms操作(虽然它仍然不会做你所期望的)。

+0

那么为什么我可以在Quick Watch中修改它们?没关系,那也适用于结构的副本,呃为什么结构还存在? – bevacqua 2010-09-24 19:28:07

+1

@Nico:结构有一个目的,但*可变*结构几乎从来没有做过。 – 2010-09-24 19:30:08

+1

@Nico:你正在做的是修改一个副本,然后扔掉。它本质上是一个没有操作。 – 2010-09-24 20:40:41