6

假设我有一个类,它的属性是字典<string,bool>,使用对象初始化器我可以使用这种语法(我认为它看起来很干净):

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

但是,在初始化程序之外我不能这样做:

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

为什么初始化器是一个特例?我冒昧地猜测它与 LINQ 要求、协方差或诸如此类的东西有关,但感觉有点不一致,不能在任何地方使用那种初始化程序......

4

3 回答 3

11

这个问题有点令人困惑,因为这个问题与 LINQ 无关,与泛型方差无关,并且具有集合初始化器和对象初始化器。真正的问题是,据我所知“为什么在对象创建表达式之外使用集合初始化器是不合法的?

这里的相关设计原则是,一般来说,我们希望创建和初始化对象的操作在其中的某处包含“new”一词,作为向读者发出的信号,表明这里正在创建对象。(是的,在 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 附加到构造函数分配的现有列表中。因此,您建议的语法对于是否创建新列表是模棱两可和令人困惑的。

提议的功能既令人困惑又不必要,因此不太可能很快实现。

于 2011-01-23T16:38:36.527 回答
2

这个限制比 LINQ 早得多。即使回到 C 你也​​可以写

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

但是您不能使用此语法将值分配给数组。

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

于 2011-01-23T13:00:32.183 回答
0

考虑到您的语法会在运行时抛出 a 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在运行时生成 a。

如果您在 的 ctor 中创建 Dictionary Test,则类初始化程序会生成一系列Add语句,这是初始化程序中的语法糖(对于IEnumerables)。

由于我们无法看到或想象的不可预见的副作用,这可能没有针对普通代码引入。Eric Lippert 可能会提供帮助,因为他可能对手头的事情有更多的了解。

于 2011-01-23T12:56:59.443 回答