15

我一直认为这两种方式都很好。然后做了这个测试并意识到重新分配是不允许的:

int[] a = {0, 2, 4, 6, 8};

工作正常但不是:

int [ ] a;
a = { 0, 2, 4, 6, 8 };

这有什么技术原因吗?我想我会在这里问这个问题,因为这种行为是我直觉上所期望的。

4

2 回答 2

21

首先,让我们把条款弄对。那不是集合初始化程序。那是一个数组初始化器。集合初始值设定项始终遵循集合类型的构造函数。数组初始值设定项仅在本地或字段声明初始值设定项或数组创建表达式中是合法的。

您完全正确地注意到这是一个奇怪的规则。让我准确地描述它的怪异之处:

假设你有一个方法 M 需要一个整数数组。所有这些都是合法的:

int[] x = new[] { 10, 20, 30 };
int[] y = new int[] { 10, 20, 30 };
int[] z = new int[3] { 10, 20, 30 };
M(new[] { 10, 20, 30 });
M(new int[] { 10, 20, 30 });
M(new int[3] { 10, 20, 30 });

int[] q = {10, 20, 30}; // legal!
M( { 10, 20, 30 } ); // illegal!

似乎“单独的”数组初始化程序应该在“装饰”的任何地方都是合法的,或者在任何地方都不合法。奇怪的是,这个伪表达式只在初始化器中有效,在其他任何合法的表达式中都没有。

在批评和捍卫这一选择之前,我首先想说的是,这种差异是历史偶然的。没有令人信服的充分理由。如果我们可以在不破坏代码的情况下摆脱它,我们会的。但我们不能。如果我们今天再次从头开始设计 C#,我认为没有“new”的“单独”数组初始值设定项不是有效语法的可能性很大。

所以,让我首先给出一些为什么不应该允许数组初始值设定项作为表达式并且应该允许在局部变量初始值设定项中的原因。然后我会给出一些相反的理由。

不应将数组初始值设定项用作表达式的原因:

{数组初始值设定项违反了总是意味着引入新代码块的nice 属性。IDE 中的错误恢复解析器在您键入时进行解析,喜欢使用大括号作为一种方便的方式来判断语句何时不完整。如果你看到:

if (x == M(
{ 
   Q(

那么代码编辑器很容易猜到你)){. 编辑器会假设这Q(是一个语句的开始,它没有结束。

但是,如果数组初始值设定项是合法的表达式,那么可能缺少)})){} Q.

其次,作为表达式的数组初始值设定项违反了所有堆分配在某处都有“新”的好原则。

字段和本地初始化程序中应允许使用数组初始化程序的原因:

请记住,数组初始值设定项是在 v1.0 中添加到语言中的,在隐式类型本地变量、匿名类型或数组上的类型推断之前。过去我们没有令人愉快的“new[] { 10, 20, 30}”语法,所以如果没有数组初始化器,你不得不说:

int[] x = new int[] { 10, 20, 30 };

这似乎非常多余!我明白他们为什么要从那里得到那个“新的 int []”。

当你说

int[] x = { 10, 20, 30 };

它在语法上没有歧义;解析器知道这是一个数组初始化器,而不是代码块的开头(与我上面提到的情况不同。)也不是类型不明确的;很明显,初始化器是上下文中的整数数组。

因此,该论点证明了为什么在 C# 1.0 中允许在本地和字段初始值设定项中使用数组初始值设定项,但在表达式上下文中却不允许。

但这不是我们今天所处的世界。如果我们今天从头开始设计它,我们可能不会有没有“新”的数组初始值设定项。当然,现在我们意识到更好的解决方案是:

var x = new[] { 10, 20, 30 };

并且该表达式在任何情况下都有效。如果您认为合适,您可以在“声明”一侧或“初始化程序”一侧显式键入它=,或者您可以让编译器推断任一侧或两者的类型。

所以,总结一下,是的,你是对的,数组初始值设定项只能在本地和字段声明中但不能在表达式上下文中是不一致的。十年前这是有充分理由的,但在具有类型推断的现代世界中,已经没有太多充分的理由了。在这一点上,这只是一个历史意外。

于 2011-12-24T01:10:47.663 回答
1

最多是:

    int [] a;// ={1,2,3,4};
    a = new [] {1, 2, 3, 4};

在 VB 中的工作方式与声明相同,更容易 xD

Dim a() As Integer '={1,2,3,4}
a = {1, 2, 3, 4}
于 2011-12-23T22:52:17.687 回答