Инициализация свойства списка без "нового списка" вызывает исключение 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" }
}
};
Ответы
Ответ 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
Ссылка на нуль всегда может быть проверена во время компиляции. Хотя компилятор иногда предупреждает об использовании переменной до ее назначения. Компилятор работает правильно. Это ошибка времени выполнения.