【问题标题】:C# Nested initialization strangenessC#嵌套初始化奇怪
【发布时间】: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 } } };

假设这是替换现有成员的一些不寻常的符号。现在初始化抛出一个StackOverflowException

所以我的问题是,为什么表达式甚至可以编译?它应该做什么?我觉得我一定错过了一些非常明显的东西。

【问题讨论】:

  • 堆栈溢出仅仅是因为创建Foo 将创建一个Dictionary 并创建一个Foo 以添加到它,这反过来又创建一个DictionaryFoo 等等。
  • 请注意,您可以将其更改为Baz = { {1, new Foo { Bar = {4,5,6}}}}; 以使其工作,因为该符号使用DictionaryAdd(Tkey, TValue),在这种情况下,如果没有new Foo,它将无法编译。跨度>

标签: c# syntax semantics c#-6.0


【解决方案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;

你的初始化版本会抛出一个StackOverflowException,因为Foo的初始化器需要创建一个Foo的新实例,它需要创建一个Foo等的新实例。

【讨论】:

  • StackOverflowException 是一个愚蠢的疏忽。不过,我不知道规范的这一部分。谢谢
  • 我还是不明白。 “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) 代替,这个表示法会非常简洁明了
猜你喜欢
  • 2011-02-22
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多