Почему этот инициализатор вложенного объекта генерирует исключение нулевой ссылки?
Следующий тестовый пример генерирует исключение с нулевой ссылкой, когда он пытается присвоить Id объекту, который является нулевым, поскольку в коде отсутствует "новый R" перед инициализатором объекта.
Почему это не поймано компилятором? Почему это разрешено, в каких случаях это будет значимым конструктом?
[TestClass]
public class ThrowAway
{
public class H
{
public int Id { get; set; }
}
public class R
{
public H Header { get; set; }
}
[TestMethod]
public void ThrowsException()
{
var request = new R
{
Header =
{
Id = 1
},
};
}
}
1 ответ
Компилятор не выдает предупреждение, потому что вы могли бы иметь:
public class R
{
public H Header { get; set; }
public R()
{
Header = new H();
}
}
так Header
может быть инициализирован кем-то / чем-то. Решение, если кто-то / что-то инициализирует Header
это сложная проблема (вероятно, похожая на проблему остановки)... Не то, что компилятор хочет решить за вас:-)
Из спецификаций C#:
Инициализатор члена, который указывает инициализатор объекта после знака равенства, является инициализатором вложенного объекта, то есть инициализацией внедренного объекта. Вместо назначения нового значения полю или свойству, назначения в инициализаторе вложенного объекта обрабатываются как присвоения членам поля или свойства. Инициализаторы вложенных объектов нельзя применять к свойствам с типом значения или к полям только для чтения с типом значения.
Мы находимся в случае вложенного инициализатора и видим полужирную часть. Я этого не знал.
Теперь обратите внимание, что new R { }
по спецификации C#, 7.6.10.1 Object creation expressions
с последующим object-initializer
, в то время как Header = { }
это "чистый" 7.6.10.2 Object initializers
,