В чем разница между этими двумя вариантами выражений инициализатора коллекции?
Некоторое время я использовал 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; }
}
Когда я запускаю это, первое назначение работает нормально, но второе приводит к 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);
Это предположение верно?
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 };