Joa*_*nge 14 .net c# compiler-construction collections collection-initializer
我一直认为它在两方面都很好.然后做了这个测试并意识到它不允许重新分配:
int[] a = {0, 2, 4, 6, 8};
Run Code Online (Sandbox Code Playgroud)
工作正常但不是:
int [ ] a;
a = { 0, 2, 4, 6, 8 };
Run Code Online (Sandbox Code Playgroud)
这有什么技术原因吗?我想我会在这里问一下,因为这种行为是我直觉所期望的.
Eri*_*ert 20
首先,我们让条款正确.那不是集合初始化程序.那是一个数组初始化器.集合初始值设定项始终遵循集合类型的构造函数.数组初始值设定项仅在本地或字段声明初始值设定项或数组创建表达式中合法.
你完全正确地注意到这是一个奇怪的规则.让我准确地描述它的古怪:
假设您有一个采用一组int的方法M. 所有这些都是合法的:
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 });
Run Code Online (Sandbox Code Playgroud)
但
int[] q = {10, 20, 30}; // legal!
M( { 10, 20, 30 } ); // illegal!
Run Code Online (Sandbox Code Playgroud)
似乎"孤独"阵列初始化器应该在任何地方都是合法的,"装饰"阵列初始化器应该是合法的,或者无处可去.奇怪的是,这个伪表达只在初始化器中有效,而不是表达式合法的其他任何地方.
在我批评和捍卫这一选择之前,我想说,首先,这种差异是一次历史性事故.这没有令人信服的好理由.如果我们可以在不破坏代码的情况下摆脱它,我们会.但我们做不到.如果我们今天再次从头开始设计C#,我认为没有"new"的"孤独"数组初始化程序不是一个有效的语法.
所以,让我首先说明为什么不应该允许数组初始值设定项作为表达式,并且应该允许在局部变量初始值设定项中使用.然后我会给出相反的一些理由.
不应允许数组初始值设定项作为表达式的原因:
数组初始值设定项违反了nice属性,它{总是意味着引入了一个新的代码块.在您键入时解析的IDE中的错误恢复解析器喜欢使用大括号作为判断语句何时不完整的便捷方式; 如果你看到:
if (x == M(
{
Q(
Run Code Online (Sandbox Code Playgroud)
然后代码编辑器很容易猜到你在))之前失踪了{.编辑将假设这Q(是一个陈述的开头而且它没有结束.
但是,如果数组的初始化是合法的表情那么它可能是现在缺少的是)})){} 下面的Q.
其次,数组初始值设定项作为表达式违反了所有堆分配在其中具有"新"的好原则.
在字段和本地初始值设定项中应允许数组初始值设定项的原因:
请记住,在隐式类型化的本地,匿名类型或数组类型推断之前,数组初始值设定项已添加到v1.0中的语言中.回到那一天,我们没有令人愉快的"new [] {10,20,30}"语法,所以没有数组初始值设定项,你不得不说:
int[] x = new int[] { 10, 20, 30 };
Run Code Online (Sandbox Code Playgroud)
这看起来很多余!我可以看出为什么他们想要从那里获得"new int []".
当你说
int[] x = { 10, 20, 30 };
Run Code Online (Sandbox Code Playgroud)
它在语法上不明确; 解析器知道这是一个数组初始化器而不是代码块的开头(与我上面提到的情况不同.)它也不是类型模糊的; 很明显,初始化器是来自上下文的一组int.
因此,该论证证明了为什么在C#1.0中,数组初始值设定项在本地和字段初始值设定项中是允许的,而在表达式上下文中则不允许.
但那不是我们今天所处的世界.如果我们今天从头开始设计这个,我们可能没有没有"新"的数组初始化器.现在我们当然意识到更好的解决方案是:
var x = new[] { 10, 20, 30 };
Run Code Online (Sandbox Code Playgroud)
并且该表达式在任何上下文中都有效.您可以=在您认为合适的"声明"侧或"初始化程序"侧明确键入它,或者您可以让编译器推断出任何一方或两者的类型.
总而言之,是的,你是对的,数组初始化器只能在本地和字段声明中,而不能在表达式上下文中.十年前有充分的理由,但在具有类型推理的现代世界中,它已经不再是一个很好的理由了.在这一点上,这只是一次历史性事故.