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: {
上述缩短的数组初始化程序并非在每个语句中都有效。
并且可能还有更多这样的不一致...
似乎错误版本是正确的,因为它们符合定义的语法,而非错误版本(对于类似情况)是语言创建的结构,只是为了使语言易于编码。
但它不应该在我们使用它的每个地方都保持一致吗?
案例 1 是 C# 语言规范.
明确涵盖的特例
来自 §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;
,那么它 将 起作用,因为当然,它现在是一个常量。
案例 2 由 new
运算符的功能启用。
来自 §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}
在可以从值推断出类型的情况下。
我正在学习 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: {
上述缩短的数组初始化程序并非在每个语句中都有效。
并且可能还有更多这样的不一致...
似乎错误版本是正确的,因为它们符合定义的语法,而非错误版本(对于类似情况)是语言创建的结构,只是为了使语言易于编码。
但它不应该在我们使用它的每个地方都保持一致吗?
案例 1 是 C# 语言规范.
明确涵盖的特例来自 §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;
,那么它 将 起作用,因为当然,它现在是一个常量。
案例 2 由 new
运算符的功能启用。
来自 §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}
在可以从值推断出类型的情况下。