为什么不允许在重新赋值时使用集合初始化式
本文关键字:集合 初始化 赋值 不允许 新赋值 为什么 | 更新日期: 2023-09-27 18:18:39
我一直认为这两种方式都很好。然后做了这个测试,发现它在重新赋值时是不允许的:
int[] a = {0, 2, 4, 6, 8};
可以,但不能:
int [ ] a;
a = { 0, 2, 4, 6, 8 };
有什么技术上的原因吗?我想我应该在这里问一下,因为这种行为是我直觉所期望的。
首先,让我们把术语弄正确。这不是集合初始化式。这是一个数组初始化器。集合初始化项总是跟在集合类型的构造函数之后。数组初始化式仅在局部或字段声明初始化式中合法,或在数组创建表达式中合法。
你完全正确地注意到这是一个奇怪的规则。让我来准确地描述一下它的怪异之处:
假设你有一个方法M,它接受一个int型数组。这些都是合法的:
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的"lone"数组初始化器将不是有效语法的可能性很大。
那么,让我首先给出一些原因,为什么数组初始化式不应该被允许作为表达式,而应该被允许在局部变量初始化式中使用。然后我会给出一些相反的理由。
数组初始化式不允许作为表达式的原因:
数组初始化项违反了{
总是意味着引入一个新的代码块的nice属性。IDE中的错误恢复解析器在您键入时进行解析,喜欢使用大括号作为一种方便的方式来判断语句何时不完整;如果你看到:
if (x == M(
{
Q(
那么代码编辑器很容易猜到您在{
之前缺少))
。编辑器将假定Q(
是语句的开头,而缺少语句的结尾。
但是如果数组初始化式是合法表达式,那么可能缺少的是)})){}
紧跟在之后的Q
.
第二,数组初始化式作为表达式违反了所有堆分配中都有"new"的好原则。
在字段和局部初始值设定项中允许数组初始值设定项的原因:
请记住,在v1.0版本中,在隐式类型化局部变量、匿名类型或数组类型推断之前,数组初始化器被添加到语言中。在过去,我们没有令人愉快的"new[]{10,20,30}"语法,所以如果没有数组初始化器,您必须说:
int[] x = new int[] { 10, 20, 30 };
看起来很多余!我可以理解为什么他们想把"new int[]"去掉。
当你说
int[] x = { 10, 20, 30 };
在语法上没有歧义;解析器知道这是一个数组初始化器,而不是代码块的开始(不像我上面提到的情况)。它也不是类型二义的;很明显,初始化式是一个来自上下文的int型数组。
所以这个参数解释了为什么在c# 1.0中数组初始化器允许在局部和字段初始化器中,而不允许在表达式上下文中。
但这不是我们今天的世界。如果我们现在从头开始设计,我们可能不会有没有"new"的数组初始化式。当然,现在我们认识到更好的解决办法是:
var x = new[] { 10, 20, 30 };
,该表达式在任何上下文中都有效。如果您认为合适,您可以在=
的"声明"端或"初始化"端显式地键入它,或者您可以让编译器推断其中一方或两者的类型。
所以,总结一下,是的,你是对的,数组初始化器只能在局部和字段声明中使用,而不能在表达式上下文中使用,这是不一致的。十年前有一个很好的理由,但在有类型推断的现代世界里,不再有什么好的理由了。这只是历史的偶然。
可能是:
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}