2016-11-16 49 views
0

我学习C#和跨越,使我对它的语法有点不舒服了几件事情来了。不一致的C#语言的语法

案例1

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

在第一条语句编译器隐蒙上文字10(类型为int)以字节,相反它不会做的第三条语句相同。

案例2

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

以上缩短阵列初始化不会每个语句工作。

,可能有更多的这种不一致......

看来错误的版本是正确的,因为这些都是按照规定的语法,并没有错误版本(类似的情况)是语言创建结构只是使语言易于编码。

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

+8

你不是指语法,而是语法。 –

+4

数组初始化只能在初始化数组时使用,而不能在数组初始化后使用。 “初始化”是指在此情况下“构建时”。你不能用这个语法分开初始化和声明。 –

+0

@MatthewWatson - 'numbers2'只被声明,即它尚未初始化。 –

回答

10

案例1是一种特殊的情况下,由C#语言规范明确地覆盖。

§6.1.9隐式常量表达式转换

隐式常量表达式转换允许以下 转化:

•类型的常量表达式(§7.19) int可以是 转换为sbyte,byte,short,ushort,uint或ulong类型,只要提供 常量表达式的值在 destina范围内类型。

•long类型的常量表达式可以是 转换为ulong类型,前提是常量表达式 的值不是负数。

因为变量ten未声明为const那么上述规则不适用,并没有隐式转换是允许的,你会得到一个编译错误。

请注意,如果你改变tenconst int ten = 10;那么工作,因为,当然,它现在是一个常数。

案例2通过运营商new的功能启用。

§1。8个阵列

新操作者允许的数组元素的初始值,使用数组初始化,这是定界符{和}之间的表达式列表中指定。

以下示例使用三个元素分配并初始化一个int []。

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

请注意,数组的长度是从{和}之间的表达式数推断的。局部变量和字段声明可以进一步缩短,使得数组类型不必重述。

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

观察它如何让你忽略new关键字,即使它是实际使用的幕后操作者new

因此,由于此语法糖由new运算符提供,因此只能在隐式使用new时使用。

在您的例子,当你单独的声明和初始化你仍然可以部分地使用这个语法,但你必须明确地使用new关键字:

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

现在你可能会说,编译器可能允许没有new的语法,因为它知道numbers2的类型,并且可以推断出存在{}意味着它必须是数组初始化。然而,这需要一个新的规则,我想像语言设计者并不认为它会被用来证明添加它是正确的。

+0

谢谢你的回答。 $ 6.1.9很好地解释了案例1。 对于案例2,我觉得语法糖也应该支持第二种说法。 –

+1

@SurajGharat我怀疑语言设计师并不是真的想要支持将分离声明和分配放在必要之外 - 为此添加明确的支持是鼓励应该被忽视的编程实践! –

4

在case1中,您正在使用文字进行初始化。这

byte b = 10; 

是好的,因为文字“10”是一个有效的字节。将变量赋值给另一个变量而不是文字是不一样的。 在下面的例子,想象一下,如果我们这样做:

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

第一种情况,只是因为C#是试图尽力解释“10”文字作为一个字节的相当不错。它可以这样做,因为它在编译时有的值,它是0..255。当从ten分配值时,它无法知道值被限制为0..255,因此它必须失败或静默截断。在C#的情况下,行为是失败的。

在情况2中,您正在使用“数组初始值设定语法”。奇怪的是,这仅适用于数组初始化程序而不是作为表达式使用。我实际上不确定这是为什么,也许是因为语法模糊。与您可能认为的相反,表达式{1, 2, 3}而不是new int[] {1, 2, 3}的简写,它只在初始化程序中使用时才起作用。

如果你想你(也许)拟在个案2中,你将不得不使用全(非初始化)表达什么:

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

编辑:正如在评论中指出有非初始化程序数组创建的简写:您可以像这样删除数组类型,只有在可以从值中推断出类型的情况下才能执行new[] {10, 20, 30}

+0

在这种特殊情况下,数组创建的'int'部分可以被删除:'new [] {10,20,30}'将创建一个'int []',因为每个项都是'int' 。 – Kyle

+0

添加到答案中,谢谢。 –