Порядок присваиваний в объекте-инициализаторе при использовании вложенных объектов
У меня есть следующий код, создающий экземпляр 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
был полностью создан.