2014-09-26 106 views
7

好吧,让我们有一些代码:的IList <mutable_struct> VS mutable_struct []

//I complie nicely 
ValueType[] good = new ValueType[1]; 
good[0].Name = "Robin"; 

//I don't compile: Cannot modify expression because its not a variable 
IList<ValueType> bad = new ValueType[1]; 
bad[0].Name = "Jerome"; 

struct ValueType 
{ 
    public string Name; 
} 

什么恰恰是怎么回事,导致该编译器却步幕后?

//Adding to watch the following 
good.GetType().Name //Value = "ValueType[]" It's a ValueType array. 
bad.GetType().Name //Value = "ValueType[]" Also a ValueType array. 

编译器阻止我修改要更改的对象副本的成员。但为什么从这个数组中创建一个副本?

多一点研究牵扯出:

var guess = (ValueType[]) bad; 
guess[0].Name="Delilah"; 

现在,你有什么感想bad[0].Name是什么?没错,这是“Delilah”。

+1

编译器很慷慨,它会阻止你修改'Name'的副本。看看[修改字典中的结构变量](http://stackoverflow.com/questions/6255305/modify-struct-variable-in-a-dictionary) – 2014-09-26 13:30:27

+0

@YuvalItzchakov是的,它是非常有用的。为什么在第二种情况下复制,而不是在第一种情况下复制? – Robino 2014-09-26 13:31:01

+0

您链接到我的qn已经upvoted。但是,它非常明显地创建了一个值类型的副本。在我的例子中,它感觉有点微妙。 – Robino 2014-09-26 13:33:31

回答

7

为什么值类型与所述IList<ValueType>复制返回而不是从阵列

因为数组是编译器知道的一个内置的构建体。它的运算符[]具有内置语义,它在数组本身内为编译器提供可修改的引用。

另一方面,当编译器处理一个接口时,它知道它返回了一个值类型的副本,该值正在尝试修改。换句话说,编译器以不同方式查看IList的运算符[]和数组的运算符[]

注意:不用说,这个练习纯属学术价值,因为mutable structs are evil

+0

流行的可变引用类型同样很糟糕,只是方式稍有不同。 – CodesInChaos 2014-09-26 13:54:47