C#嵌套初始化奇怪
Posted
技术标签:
【中文标题】C#嵌套初始化奇怪【英文标题】:C# Nested initialization strangeness 【发布时间】:2017-05-18 20:35:07 【问题描述】:在这些初始化语句可以编译的前提下
List<int> l = new List<int> 1, 2, 3 ;
Dictionary<int, int> d = new Dictionary<int, int> [1] = 11, [2] = 22 ;
Foo f = new Foo Bar = new List<int>() ;
这不会
List<int> l = 1, 2, 3 ;
Dictionary<int, int> d = [1] = 11, [2] = 22 ;
Foo f = Bar = new List<int>() ;
我有一个关于嵌套初始化的问题。给定以下课程
public class Foo
public List<int> Bar get; set; = new List<int>();
public Dictionary<int, Foo> Baz get; set; = new Dictionary<int, Foo>();
我偶然发现你实际上可以这样做:
Foo f = new Foo
Bar = 1, 2, 3 ,
Baz =
[1] =
Bar = 4, 5, 6
;
当它编译时会抛出一个KeyNotFoundException
。所以我将属性更改为
public List<int> Bar get; set; = new List<int> 4, 5, 6 ;
public Dictionary<int, Foo> Baz get; set;
= new Dictionary<int, Foo> [1] = new Foo Bar = new List<int>() 1, 2, 3 ;
假设这是替换现有成员的一些不寻常的符号。现在初始化抛出一个***Exception
。
所以我的问题是,为什么表达式甚至可以编译?它应该做什么?我觉得我一定错过了一些非常明显的东西。
【问题讨论】:
堆栈溢出仅仅是因为创建Foo
将创建一个Dictionary
并创建一个Foo
以添加到它,这反过来又创建一个Dictionary
与Foo
等等。
请注意,您可以将其更改为Baz = 1, new Foo Bar = 4,5,6;
以使其工作,因为该符号使用Dictionary
的Add(Tkey, TValue)
,在这种情况下,如果没有new Foo
,它将无法编译。跨度>
【参考方案1】:
所以我的问题是,为什么表达式甚至可以编译?
它是一个带有集合初始值设定项的对象初始值设定项。来自 C# 规范第 7.6.10.2 节:
在等号之后指定集合初始值设定项的成员初始值设定项是嵌入式集合的初始化。初始化器中给出的元素被添加到字段或属性引用的集合中,而不是为字段或属性分配新集合。
所以你的code代码大致相当于:
Foo tmp = new Foo();
tmp.Bar.Add(1);
tmp.Bar.Add(2);
tmp.Bar.Add(3);
tmp.Baz[1].Bar.Add(4); // This will throw KeyNotFoundException if Baz is empty
tmp.Baz[1].Bar.Add(5);
tmp.Baz[1].Bar.Add(6);
Foo f = tmp;
你的初始化版本会抛出一个***Exception
,因为Foo
的初始化器需要创建一个Foo
的新实例,它需要创建一个Foo
等的新实例。
【讨论】:
***Exception 是一个愚蠢的疏忽。不过,我不知道规范的这一部分。谢谢 我还是不明白。 “Foo”的对象实例是在哪一行代码中递归创建的? 不应该是temp.Baz[1].Bar.Add(4)
吗?
@Sung 如果您的意思是字典中的Foo
,则没有创建Foo
,假设索引1 处已经有Foo
,它只是在添加值给它Bar
。
我想知道他们对“无类型”字典初始化有什么用例。如果用(tmp.Baz.ContainsKey(1) ? tmp.Baz[1] : tmp.Baz[1] = new ...).Bar.Add(4)
代替,这个表示法会非常简洁明了以上是关于C#嵌套初始化奇怪的主要内容,如果未能解决你的问题,请参考以下文章