21

为什么我不能将数组初始值设定项与隐式类型变量一起使用?

string[] words = { "apple", "strawberry", "grape" };                 // legal
string[] words = new string[]{ "apple", "strawberry", "grape" };     // legal
var words = new []{ "apple", "strawberry", "grape" };                // legal
var words = new string[]{ "apple", "strawberry", "grape" };          // legal

var words = { "apple", "strawberry", "grape", "peach" };             // ILLEGAL

这种限制有技术原因吗?为什么它不能像它那样推断类型:

var number = 10;
var text = "Hello";

编译器清楚地知道我要做什么,它只是不允许这样做:

CS0820:无法将数组初始值设定项分配给隐式类型的本地


更新:我使用四种合法的数组声明方法编译了一个程序,它生成了相同的 IL: http: //pastebin.com/28JDAFbL

这只会增加我的困惑。并且“它是这样的,因为规范是这样说的”并没有什么帮助。为什么规格是这样的?这里的理由是什么?

4

3 回答 3

35

为什么我不能将数组初始值设定项与隐式类型变量一起使用?为什么规格是这样的?这里的理由是什么?

做出此决定时,我不在设计团队中,并且设计说明(*)对此主题保持沉默。然而,当我做出这个决定时,我询问了 2005 年在场的人。

解释平淡无奇。设计团队一开始就对数组初始值设定项语法非常不满意。坦率地说,数组初始值设定项不是表达式并且在语法上只能出现在本地或字段声明中,这真是太奇怪了。它使解析器复杂化。这似乎很奇怪

int[] x = {1};

应该是合法的,但是

M({1});

不是。

数组初始化语法还使编辑时代码分析期间的错误恢复变得复杂。假设你有类似的东西:

class C
{
    void M()
    {
        {
            int result = whatever();
            ...
        }
        {
            int result = somethingElse();
            ...
        }
    }
}

然后你开始在编辑器中输入一个新的声明:

    void M()
    {
        int[] x = 
        {
            int result = whatever();

突然之间,解析器必须以一种不会混淆即将键入“null;”的可怜用户的方式来消除歧义。显然,您不打算使用代码块初始化局部变量,但解析器完全有权说大括号在这里只能合法地成为数组初始化程序的一部分,因此它是“int 结果”出乎意料。

所以,长话短说,“经典”数组初始化器有点错误。由于向后兼容的原因,我们无法摆脱它们。但我们也不想通过允许它们在更多地方使用来鼓励它们的使用。

设计团队想出了在数组初始值设定项前加上“new[]”的想法,并将变为合法表达式,现在问题解决了。经典的数组初始值设定项错误并没有“蔓延”到语言的新领域,并且有一个简洁但可读的语法清楚地表明“你正在这里创建一个新数组”。

这个故事的寓意是:尝试第一次就正确,因为语法是永恒的。


(*) 在我的搜索中,我确实发现了一些有趣的事情:团队最初认为“var”可能不会是为该功能选择的关键字;显然它在他们身上生长。此外,一种设计要求“var”局部变量不仅是隐式类型,而且是 init-once 局部变量。显然我们从来没有实现过 init-once 局部变量。

于 2011-09-08T20:33:38.870 回答
8

您可以使用以下语法来执行此操作:

var words = new[] { "apple", "strawberry", "grape", "peach" };
于 2011-09-08T16:34:54.673 回答
5

可能是因为你没有给它任何类型,例如。它是数组、列表还是其他集合。

但是,这有效并且看起来相同,只是长了几个字符。

var words = new[]{ "apple", "strawberry", "grape", "peach" };   
于 2011-09-08T16:36:10.613 回答