C# 语言语法不一致

Inconsistency in C# language syntax

我正在学习 C#,遇到了一些让我对它的语法不太满意的事情。

案例一

byte num1 = 10;    // works
int ten = 10;
byte num2 = ten;   // Compile error: Cannot implicitly convert 'int' to byte. An explicit conversion exists.

在第一条语句中,编译器将文字 10(int 类型)隐式转换为 byte,相反,它在第三条语句中不做同样的事情。

案例二

int[] numbers1 = { 10, 20, 30 };     // works
int[] numbers2;
numbers2 = { 10, 20, 30 };          // Compiler error: Invalid expression term: {

上述缩短的数组初始化程序并非在每个语句中都有效。

并且可能还有更多这样的不一致...

似乎错误版本是正确的,因为它们符合定义的语法,而非错误版本(对于类似情况)是语言创建的结构,只是为了使语言易于编码。

但它不应该在我们使用它的每个地方都保持一致吗?

案例 1C# 语言规范.

明确涵盖的特例

来自 §6.1.9 隐式常量表达式转换:

An implicit constant expression conversion permits the following conversions:

• A constant-expression (§7.19) of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type.

• A constant-expression of type long can be converted to type ulong, provided the value of the constant-expression is not negative.

因为变量ten没有声明为const所以上面的规则不适用,不允许隐式转换,你会得到一个编译错误。

请注意,如果您将 ten 更改为 const int ten = 10;,那么它 起作用,因为当然,它现在是一个常量。

案例 2new 运算符的功能启用。

来自 §1.8 数组:

The new operator permits the initial values of the array elements to be specified using an array initializer, which is a list of expressions written between the delimiters { and }.

The following example allocates and initializes an int[] with three elements.

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

Note that the length of the array is inferred from the number of expressions between { and }. Local variable and field declarations can be shortened further such that the array type does not have to be restated.

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

观察它如何允许您省略 new 关键字,即使它实际上在幕后使用 new 运算符。

所以因为这个语法糖是由new运算符提供的,所以只能在隐式使用new时使用。

在您的示例中,当您将声明和初始化分开时,您仍然可以部分使用此语法,但您必须随后明确使用 new 关键字:

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

现在你可以争辩说编译器 可以 允许没有 new 的语法,因为它知道 numbers2 的类型并且可以推断存在{} 意味着它必须是一个数组初始化。但是,这将需要一个新规则,我想语言设计者认为它的使用不足以证明添加它是合理的。

在案例 1 中,您正在使用文字进行初始化。这个

byte b = 10;  

没问题,因为文字“10”是一个有效字节。将变量分配给另一个变量而不是文字不是一回事。 在下一个示例中,想象一下如果我们这样做:

int ten = 10;
ten = 100000; // evil
byte b = ten;

第一种情况之所以奏效,是因为 C# 非常擅长将“10”文字解释为一个字节。它可以做到这一点,因为它在编译时具有可用的 value,并且它是 0..255。从 ten 分配值时,它不知道该值被限制为 0..255 因此它必须失败或静默截断。对于 C#,行为是失败。

在情况 2 中,您使用的是 "array initializer syntax"。有点奇怪的是,这仅可用于数组 initializers 而通常不能用作表达式。我实际上不确定为什么会这样,也许是因为语法歧义。与您的想法相反,表达式 {1, 2, 3} 对于 new int[] {1, 2, 3} 而言是 而不是 shorthand,它仅在初始化程序中使用时才有效。

如果你想做你(可能)在案例 2 中想要做的事情,你将不得不使用完整的(非初始化)表达式:

int[] numbers1 = new int[] { 10, 20, 30 };     
int[] numbers2;
numbers2 = new int[] { 20, 30, 40 };

编辑:正如评论中指出的那样,一个shorthand用于非初始化数组创建:你可以像这样删除数组类型,并且只做new[] {10, 20, 30} 在可以从值推断出类型的情况下。