Подтвердить что ты не робот

Инициализация свойства списка без "нового списка" вызывает исключение NullReferenceException

using System;
using System.Collections.Generic;

class Parent
{
   public Child Child { get; set; }
}

class Child
{
   public List<string> Strings { get; set; }
}

static class Program
{
   static void Main() {
      // bad object initialization
      var parent = new Parent() {
         Child = {
            Strings = { "hello", "world" }
         }
      };
   }
}

Вышеупомянутая программа компилируется отлично, но сбой при выполнении с ссылкой на объект не установлен в экземпляр объекта.

Если вы заметили в приведенном выше фрагменте, у меня есть пропущенный новый при инициализации дочерних свойств.

Очевидно, что правильный способ инициализации:

      var parent = new Parent() {
         Child = new Child() {
            Strings = new List<string> { "hello", "world" }
         }
      };

Мой вопрос в том, почему компилятор С# не жалуется, когда видит первую конструкцию?

Почему синтаксис с инициализацией сломанной инициализации?

      var parent = new Parent() {
         Child = {
            Strings = { "hello", "world" }
         }
      };
4b9b3361

Ответ 1

Второй синтаксис действителен для свойств readonly. Если вы измените код для инициализации свойств Child и Strings в соответствующих конструкторах, синтаксис будет работать.

class Parent
{
    public Parent()
    {
        Child = new Child();
    }

    public Child Child { get; private set; }
}

class Child
{
    public Child()
    {
        Strings = new List<string>();
    }
    public List<string> Strings { get; private set; }
}

static class Program
{
    static void Main()
    {
        // works fine now
        var parent = new Parent
        {
            Child =
            {
                Strings = { "hello", "world" }
            }
        };

    }
}

Ответ 2

Это не сломленный синтаксис, это тот, кто использует инициализатор объекта для свойства, которое просто не создается. То, что вы написали, можно развернуть до

var parent = new Parent();
parent.Child.Strings = new List<string> { "hello", "world" };

Что выбрал NullReferenceException: вы пытаетесь присвоить свойство Strings, содержащееся в свойстве Child, в то время как Child все еще null. Сначала, используя конструктор для создания экземпляра Child, позаботимся об этом.

Ответ 3

Нет ничего плохого в инициализации, но он пытается инициализировать объекты, которые не существуют.

Если классы имеют конструкторы, которые создают объекты, выполняется инициализация:

class Parent {
  public Child Child { get; set; }
  public Parent() {
    Child = new Child();
  }
}

class Child {
  public List<string> Strings { get; set; }
  public Child() {
    Strings = new List<string>();
  }
}

Ответ 4

Кажется, вы неправильно поняли, что делает инициализатор коллекции.

Это простой синтаксический сахар, который преобразует список в фигурные скобки в последовательность вызовов метода Add(), которые должны быть определены в инициализированном объекте коллекции.
Таким образом, ваш = { "hello", "world" } имеет тот же эффект, что и

.Add("hello");
.Add("world");

Очевидно, что это приведет к ошибке с исключением NullReferenceException, если коллекция не создана.

Ответ 5

Ссылка на нуль всегда может быть проверена во время компиляции. Хотя компилятор иногда предупреждает об использовании переменной до ее назначения. Компилятор работает правильно. Это ошибка времени выполнения.