Учитывая следующие 2 класса (VS 2015 + .Net 4.5) с полностью изменяемыми свойствами:
class Wrapped
{
public int A {get; set;}
public int B {get; set;}
}
class Wrapper
{
public int X {get; set;}
public Wrapped Y {get; set;}
public Wrapper()
{
Y = new Wrapped { A = 5, B = 10 };
}
}
Я был заинтригован, обнаружив, что Resharper 8.x рекомендовал использовать синтаксис инициализатора объекта (UseObjectOrCollectionInitializer
) в следующем сценарии вложенной инициализации, где я предполагал только частичное присвоение обернутого объекта — я хотел, чтобы остальные свойства экземпляра Wrapped
должны сохранять любые значения по умолчанию, выданные конструктором класса Wrapper
:
// My Original code
var demo1 = new Wrapper
{
X = 5
};
demo1.Y.B = 23;
// Resharper's refactoring suggestion
var demo2 = new Wrapper
{
X = 5,
Y = { B = 23 }
};
Изначально я предполагал, что рефакторинг может быть синтаксическим сахаром для:
new Wrapper
{
X = 5,
Y = new Wrapped { B = 23 }
};
Что, очевидно, не совпадает с моим кодом, так как он будет расточительно создавать и назначать свойство Y
дважды (один раз в конструкторе по умолчанию Wrapper's
и один раз в назначении Y
, и, что еще хуже, в установщике он потеряет все другие значения свойств, назначенные конструктором Wrapper's
, так как он примет любые значения, назначенные конструктором Wrapped
.
Однако после дизассемблирования IL с помощью LinqPad я был поражен правильностью Resharper, а именно тем, что синтаксис инициализатора:
Y = { B = 23 }
эквивалентно явному
demo1.Y.B = 23;
Итак, мой вопрос: есть ли официальная ссылка на этот "частичный" (т.е. нереконструированный) синтаксис присваивания в синтаксисе инициализации объекта. Мне не удалось легко найти его в MSDN, например. Инициализаторы объектов и коллекций, так что я могу взвесить относительные преимущества и опасности этого синтаксиса?
Изменить
Кроме того, отмечено, что, как и в случае с явным синтаксисом,
Y = { B = 23 }
Будет выброшено NullReferenceException
, если B не создан внутри конструктора Y.
Разборка ИЖ:
то есть оба demo1
и demo2
приводят к этому IL:
Wrapper..ctor
Wrapper.set_X
Wrapper.get_Y
Wrapped.set_B
В то время как demo3 приводит к неправильному
Wrapper..ctor
Wrapper.set_X
Wrapped..ctor
Wrapped.set_B
Wrapper.set_Y
Я разместил небольшой образец, показывающий различия между 1 и 2 и 3, на IdeOne здесь