我看到NRE when using array initializer in object initializer并且有更新https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6#extension-add-methods-in-collection-initializers,但我仍然无法理解。
var arr = new int[] { 1, 2, 3 }
使用stelem
生成IL代码。
但int[] arr = { 1, 2, 3 }
使用RuntimeHelpers.InitializeArray
生成IL代码。我认为它正在使用Array.Add
扩展方法,该方法就是答案。
但是在对象初始化器中,所有数组初始化器都会生成第二个代码。 一个例子,
new A() {
arr = new int[] { 1, 2, 3 }
}
数组arr
也是使用RuntimeHelpers.InitializingArray
创建的。那么,这并不意味着下一个代码中没有任何问题吗?
new A() {
arr = { 1, 2, 3 } // Compiler error!
}
与旧版本的c#编译器不同,它使编译器错误说system.array does not contain a definition for Add
。发生了什么?
EDIT
我认为只有没有new []
的语法会产生差异,但实际上有三个以上的元素会产生不同的IL代码。
答案 0 :(得分:3)
第二种语法(block do ... end
)是{ arr = {... } }
序列的语法糖 - 可能value.arr.Add(.)
未在构造函数中初始化,因此也就是NRE。
假设value.arr
是:
A
然后
class A {
public int[] arr {get;set}
}
与
相同var x = new A() {
arr = { 1, 2, 3 } // Compiler error!
};
修复:使用列表,没有合理的方法向数组添加元素。
如果使用其他没有var x = new A(); // note x.arr is default null here
x.arr.Add(1); // NRE is arr is list, can't compile for int[]
x.arr.Add(2);
x.arr.Add(3);
的其他类型 - 实现该代码可见的扩展方法。
为什么版本.Add
有效:
new
等同于 *
var x = new A() {
arr = new int[] { 1, 2, 3 }
};
请注意,在数组初始值设定项中,您可以将两种语法用于相同的效果,但不能在数组字段的初始值设定项中使用(All possible C# array initialization syntaxes)
var x = new A();
x.arr = new int[] { 1, 2, 3 };
而int[] x = { 10, 20, 30 }; // valid, same as int[] x = new int[]{ 10, 20, 30 };
与<{1}} 相同
* 当必须观察变化时,满足规则真的有点复杂 - 参见Eric Lippert的comment below
答案 1 :(得分:3)
在表达式上下文中,这些是合法的数组值:
new int[3] { 10, 20, 30 }
new int[] { 10, 20, 30 }
new[] { 10, 20, 30 }
在本地或成员变量初始化程序上下文中,这是一个合法的数组初始值设定项:
int[] x = { 10, 20, 30 };
这是一个合法的集合初始化程序:
List<int> x = new List<int> { 10, 20, 30 };
而且,如果X<T>
为IEnumerable<T>
并且方法为Add(T, T, T)
,则这是合法的:
X<int> x = new X<int> { { 10, 20, 30}, {40, 50, 60} };
但是在成员或集合初始化程序上下文中,不是合法数组属性初始值设定项:
new A() {
arr = { 10, 20, 30 }
}
(请注意,我在这里总结并评论了数组规则https://stackoverflow.com/a/5678393/88656)
正如我所理解的那样,问题是&#34;为什么不呢?&#34;
答案是&#34;没有充分理由&#34;。它只是C#语法的奇怪之处以及对象和集合初始化器的规则。
我多次考虑修复这种奇怪之处,但总有一些事情与我的时间有关;它是一个基本上没有人受益的解决方案,因为解决方法非常简单。
我猜想没有什么能阻止C#团队设计,指定,实施,测试和发布该功能,除了还有大约一百万个其他功能可以更好地利用他们的时间
如果您对此感到强烈,那么编译器就是开源的;随意提出这个功能并提倡它。或者,就此而言,实施它并提交拉取请求。 (在之后提出功能。)
在实现您想要的功能之前,您只需使用三个&#34;表达式中的一个&#34;上面列出的表格。这样做并不累赘。