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

本文关键字:类型变量 一起 不能 数组 初始化 为什么 | 更新日期: 2023-09-27 18:08:05

为什么我不能使用隐式类型变量的数组初始化器?

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

这只会增加我的困惑。而"之所以这样,是因为说明书上这么说"也没什么帮助。为什么规格是这样的?这里的基本原理是什么?

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

为什么我不能使用隐式类型变量的数组初始化器?为什么规格是这样的?这里的基本原理是什么?

做出这个决定时我不在设计团队,设计说明(*)对这个主题保持沉默。然而,我问了一个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 locals

可以使用以下语法:

var words = new[] { "apple", "strawberry", "grape", "peach" };

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

然而,这工作和看起来一样,只是长了几个字符。

var words = new[]{ "apple", "strawberry", "grape", "peach" };