2011-01-23 106 views
6

有人说我有一个属性,它是一本字典<字符串,布尔>,使用对象初始化我可以用这句法(我觉得看起来很干净)一类:协变对象初始值设定项?

new MyClass() 
{ 
    Table = { {"test",true},{"test",false} } 
} 

然而,外我不能这样做:

this.Table = { {"test",true},{"test",false} }; 

为什么初始值设定项是一个特殊情况?我猜测它与LINQ需求,协变或什么都没有关系,但它感觉有点不一致,无法在任何地方使用这种初始化器......

+0

有趣的问题。 – 2011-01-23 12:56:37

+0

我认为编译器错误是“预期表达式”的事实是一个很大的线索。在第二个例子中,语法并不像您通常所期望的那样表示一个表达式,即没有`new`操作符。我怀疑第一个例子是有效的,因为它是一个特殊情况,编译器对语法构成表达式的内容更加宽松。宽松规则的好处是对于对象初始化语法的上下文非常有用的特殊语法,否则它看起来会很难看。 – 2011-01-23 13:45:44

回答

0

考虑到你的语法在运行时抛出NullReferenceException - 你确定你可以使用它吗?

public class Test 
{ 
    public Dictionary<string, bool> Table {get; set;} 
} 

public void TestMethod() 
{ 
    Test t = new Test { Table = { {"test", false} } }; //NullReferenceException 
} 

这编译成以下的(经由反射器):

Test <>g__initLocal3 = new Test(); 
<>g__initLocal3.Table.Add("test", 0.0M); 

正如你可以看到,Table没有初始化,从而产生NullReferenceException在运行时。

如果在Test的ctor中创建字典,类初始化程序会生成级联Add语句,这是初始化程序中的语法糖(对于IEnumerable s)。

由于我们无法看到或想象的未知副作用,因此可能没有引入正常代码。 Eric Lippert可能会帮忙,因为他可能对这件事情有更多的了解。

+2

是的,我知道,但不是完全相同的语法 – Homde 2011-01-23 12:57:43

+3

但是他不问他为什么你必须在它前面提供`新的Dictionary `。 – 2011-01-23 12:57:56

2

此限制远比LINQ旧。即使回到C,你可以写

int numbers[5] = {1, 2, 3, 4, 5}; 

但你不能用这个语法来给数组赋值。

我对C#背后的原因的猜测是,通常你不应该为两个不同的对象使用相同的引用。如果您需要将新集合分配给现有引用,则很可能您没有很好地设计代码,并且可以在定义时初始化集合,或者使用两个单独的引用而不是一个。

11

这个问题有点令人困惑,因为问题与LINQ无关,与通用方差无关,并且具有集合初始值设定项以及对象初始值设定项。真正的问题是,据我可以告诉“为什么是不合法的使用集合初始化之外的对象创建表达式的?

相关的设计在这里的原则是,在一般情况下,我们要操作的是创建和初始化对象,让它们在某个地方具有“新”字样,作为向读者发出信号的信号,即在此处发生对象创建。 (是的,这个规则在C#中有一些例外,作为读者的练习,看看你是否可以将它们命名为全部。)

按照你的方式做事情会让代码难以理解。快,这是做什么的?

d = new List<int>() { 10, 20, 30 }; 
d = { 40, 50, 60 }; 

是否第二线追加 40,50,60到现有列表?还是用新的名单取代旧名单?那里没有“新”,读者有没有期望新的对象被创建?

当你说

q = new Whatever() { MyList = { 40, 50, 60 } }; 

不创建一个新的列表;它将40,50,60添加到由构造函数分配的现有列表中。因此,你提出的语法是不明确的,并且对是否创建新列表感到困惑。

建议的功能既混乱又不必要,所以不可能很快实施。

相关问题