Порядок присваиваний в объекте-инициализаторе при использовании вложенных объектов

У меня есть следующий код, создающий экземпляр Root используя объект-инициализатор:

var r = new Root { Person = new Person { Age = 20, Name = "Hans" } };

Есть ли какая-то польза от использования инициализатора объектов? Я знаю, если бы у нас был только внутренний объект Person это было переведено примерно так:

var p = new Person();
p.Age = 20;
p.Name = 20;

Интересно, как это влияет на вложенные объекты в моем первом примере? Является Person полностью создан и назначен новому экземпляру Root или это просто переводится к чему-то вроде этого:

var r = new Root();
r.Person = new Person();
r.Person.Age = 20;          // this would call the Persons getter
r.Person.Name = "Hans";     // this would call the Persons getter

Причина, по которой я спрашиваю, заключается в том, что получатель и установщик изменяют Person для данного Root довольно сложный, и я хотел бы избежать вызова его геттеров для установки свойств для этого Person,

2 ответа

Решение

Об этом прямо говорится в 7.6.10.2 Спецификации языка C#.

Стандарт дает этот пример для "инициализатора вложенного объекта":

public class Point
{
    int x, y;
    public int X { get { return x; } set { x = value; } }
    public int Y { get { return y; } set { y = value; } }
}

public class Rectangle
{
    Point p1, p2;
    public Point P1 { get { return p1; } set { p1 = value; } }
    public Point P2 { get { return p2; } set { p2 = value; } }
}

Rectangle r = new Rectangle 
{
    P1 = new Point { X = 0, Y = 1 },
    P2 = new Point { X = 2, Y = 3 }
};

Стандарт гласит, что это имеет тот же эффект, что и:

Rectangle __r = new Rectangle();
Point __p1 = new Point();
__p1.X = 0;
__p1.Y = 1;
__r.P1 = __p1;
Point __p2 = new Point();
__p2.X = 2;
__p2.Y = 3;
__r.P2 = __p2; 
Rectangle r = __r;

Здесь вы можете увидеть, что Rectangle.P1 а также Rectangle.P2 свойства инициализируются из уже созданного Point объекты.

Это доказывает, что ответ на ваш вопрос

Полностью ли создан Person и чем назначен новый экземпляр Root?

окончательно: да.

Мы можем легко проверить это, установив точку останова в получателе для Person в пределах Root-учебный класс. При отладке мы замечаем, что это никогда не срабатывает.

Это действительно приводит к созданию следующего объектного графа:

var p = new Person();
p.Age = 20;
p.Name = "Hans";

var r = new Root();
r.Person = p;

Вы видите, что нет доступа к геттеру, чтобы установить свойства лиц, потому что Person создается первым, перед любым Root даже существует.

Это гарантирует, что Root полностью создается только если ранее Person был полностью создан.

Другие вопросы по тегам