这两个集合初始化表达式的变化有什么区别?

Tag*_*agc 20 c# collection-initializer

我一直在使用C#,但最近注意到我的一个单元测试的行为根据我使用的集合初始化表达式的变化而改变:

  • var object = new Class { SomeCollection = new List<int> { 1, 2, 3 } };
  • var object = new Class { SomeCollection = { 1, 2, 3 } };

直到这一点,我认为第二种形式只是语法糖,在语义上等同于第一种形式.然而,在这两种形式之间切换导致我的单元测试失败.

下面的示例代码演示了这一点:

void Main()
{
    var foo1 = new Foo { Items = new List<int> { 1, 2, 3} };
    var foo2 = new Foo { Items = { 1, 2, 3 } };

    foo1.Dump();
    foo2.Dump();
}

class Foo
{
    public List<int> Items { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,第一个分配工作正常,但第二个分配结果为NullReferenceException.

我的直觉是,在幕后,编译器将这两个表达式视为:

var foo1 = new Foo();
foo1.Items = new List<int> { 1, 2, 3 }; 

var foo2 = new Foo();
foo2.Items.Add(1);
foo2.Items.Add(2);
foo2.Items.Add(3);
Run Code Online (Sandbox Code Playgroud)

这个假设准确吗?

Jon*_*eet 22

是的,你的假设是准确的.如果对象初始化程序只有:

{
    Property = { ... }
}
Run Code Online (Sandbox Code Playgroud)

而不是

{
    Property = expression
}
Run Code Online (Sandbox Code Playgroud)

设置器为属性不使用-该吸气剂被使用,并且然后或者Add方法被调用,或特性返回值内.所以:

var foo = new Foo
{
    Collection = { 1 }
    Property =
    {
        Value = 1
    }
};
Run Code Online (Sandbox Code Playgroud)

相当于:

// Only the *getters* for Collection and Property are called
var foo = new Foo();
foo.Collection.Add(1);
foo.Property.Value = 1;
Run Code Online (Sandbox Code Playgroud)

与之相比:

var foo = new Foo
{
    Collection = new List<int> { 1 },
    Property = new Bar { Value = 1 }
};
Run Code Online (Sandbox Code Playgroud)

这相当于:

// The setters for Collection and Property are called
var foo = new Foo();
foo.Collection = new List<int> { 1 };
foo.Property = new Bar { Value = 1 };
Run Code Online (Sandbox Code Playgroud)