Подтвердить что ты не робот

В чем разница между этими двумя вариантами выражений инициализатора коллекции?

Я некоторое время использую С#, но недавно заметил, что поведение одного из моих модульных тестов изменилось в зависимости от того, какая вариация выражения инициализации коллекции я использовал:

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

До этого момента я предполагал, что вторая форма была просто синтаксическим сахаром и была семантически эквивалентна первой форме. Однако переход между этими двумя формами привел к провалу unit test.

Пример кода ниже демонстрирует это:

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; }
}

Когда я запускаю это, первое назначение работает отлично, а второе - в 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);

Насколько это предположение верно?

4b9b3361

Ответ 1

Да, ваше предположение верно. Если инициализатор объекта имеет только:

{
    Property = { ... }
}

а не

{
    Property = expression
}

тогда средство настройки для свойства не используется - используется геттер, а затем вызывается либо метод Add, либо свойства задаются в возвращаемом значении. Итак:

var foo = new Foo
{
    Collection = { 1 }
    Property =
    {
        Value = 1
    }
};

эквивалентно:

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

Сравните это с:

var foo = new Foo
{
    Collection = new List<int> { 1 },
    Property = new Bar { Value = 1 }
};

что эквивалентно:

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