得知c#编译器可以推断信息较少的声明,我感到很惊讶

本文关键字:声明 编译器 信息 得知 | 更新日期: 2023-09-27 18:07:41

按照时间顺序考虑下面的代码片段。注释的语句不能编译。

    var data1 = new int[3] { 1, 2, 3 };
    var data2 = new int[] { 1, 2, 3 };
    var data3 = new[] { 1, 2, 3 };
    var data4 = new[] { 1, 2, 3.0f };

data3data4的简化是可以理解的。

    int[] data5 = { 1, 2, 3 };
    //var data6 = { 1, 2, 3 };

无法推断data6的声明是可以理解的。

    var data7 = new int[] { };
    //var data8 = new [] { }; 
    //int[] data9 = new [] { };

无法推断data8的声明也是可以理解的。

我不明白的是为什么data9的信息更丰富,而data10的信息更少,可以编译。

    int[] data10 = { };
    //var data11 = { };

声明不能编译的data11也是可以理解的。

得知c#编译器可以推断信息较少的声明,我感到很惊讶

出现new关键字的情况是通常的表达式,可以在任何需要表达式的上下文中自行使用。您可以将它们用于具有赋值的声明,但它们可以用于其他上下文中,例如:

return new[] { 3 };

或:

Call(new[] { 3 });

等等。在这些new数组表达式中,类型必须与表达式本身明确。即使在左侧有变量声明,也需要这样做。

因此,data9int[] data9 = new [] { };是不合法的,因为表达式new[] { }是不合法的。它有点像:
object related9 = someBoolean ? "Yes" : new Exception();

也是非法的,因为表达式someBoolean ? "Yes" : new Exception()本身是非法的,具有不兼容的类型。这里有一个类型为object的声明,但这并不意味着右边是合法的。


示例data5data10显示了一种完全不相关的数组变量声明语法。

int[] data5 = { 1, 2, 3 };

这里,=操作符的右边是,而不是本身是表达式。这种语法要求在=符号的左边有一个显式类型的声明(所以data6是不可以的)。该语法与对象初始化器集合初始化器相关,并在c#语言中与它们一起引入,而new[] { ... }语法则稍早一些。


你应该看看Lippert的回答,然后阅读官方的c#语言规范

c#是一种不能从上下文推断类型的语言。这意味着它只能从表达式外部提取类型,反之亦然。

换句话说,您所显示的现象与以下情况下编译器无法选择正确的重载相同:

int foo();
string foo();
string x = foo();

但是,在下列情况下,它可以选择正确的重载:

void bar(int x);
void bar(string x);
string x;
bar(x);

Edit: Servy注释说lambda表达式是该规则的例外。例如:

var a = new Func<int, bool>(a => a == 1);

编译器不能推断"a => a == 1"的类型,除非从上下文中推断。