繁体   English   中英

无法理解为什么无法初始化对象初始化程序中的数组初始化程序

[英]Can't understand why array initializer in object initializer cannot compiled

在对象初始化程序中使用数组初始化程序时看到了NRE,并且进行了更新和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代码。

第二种语法( { arr = {... } } )是value.arr.Add(.)序列的语法糖-大概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 } 
};

等价于*

var x = new A();
x.arr = new int[] { 1, 2, 3 };

请注意,在数组初始化程序中,可以使用两种语法达到相同的效果,但不能在数组字段的初始化程序中使用( 所有可能的C#数组初始化语法

int[] x = { 10, 20, 30 }; // valid, same as int[] x = new int[]{ 10, 20, 30 };

new A { arr = { 10, 20, 30} } 是不一样的new A { arr = new int[3]{ 10, 20, 30} }


*当必须观察到变化时,要满足规则确实要复杂一些-请参阅下面的 Eric Lippert的评论

表达式上下文中,这些是合法的数组值:

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总结并评论了数组的规则)

据我了解,问题是“为什么不呢?”

答案是“没有充分的理由”。 这只是C#语法以及对象和集合初始化程序的规则的奇怪之处。

我曾多次考虑过解决这种奇怪的问题,但是与我的时间总是有更好的关系。 该解决方案基本上没有人受益,因为解决方法非常简单。

我猜想,除了仍有大约一百万个其他功能可以更好地利用他们的时间这一事实之外,没有什么可以阻止C#团队设计,指定,实现,测试和发布这些功能。

如果您对此有强烈的兴趣,那么编译器是开源的。 随时提出该功能并对其进行提倡。 或者,为此,实施它并提交拉取请求。 你提出的功能。)

在实现所需的功能之前,您只需要使用上面列出的三种“表达式”形式之一。 这样做并不麻烦。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM