Почему этот инициализатор вложенного объекта генерирует исключение нулевой ссылки?

Следующий тестовый пример генерирует исключение с нулевой ссылкой, когда он пытается присвоить 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,

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