Это ошибка в компиляторе С# 4.0?
Этот код успешно компилируется, но я думаю, что он не должен компилироваться. Кроме того, при запуске вы получаете NullReferenceException
. Недопустимый код - это "новая строка" в инициализации свойства Bar
.
class Bar
{
public string Name { get; set; }
}
class Foo
{
public Bar Bar { get; set; }
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo
{
Bar = { Name = "Hello" }
};
}
}
Является ли это известной ошибкой?
Ответы
Ответ 1
Почему вы думаете, что он не должен компилироваться? Это синтаксис инициализатора вложенных объектов, и клиентский код отвечает за допустимое значение для инициализации.
Из документации:
С# spec 7.5.10.2 "Инициализаторы объектов"
Инициализатор элемента, который указывает инициализатор объекта после знака равенства, является инициализатором вложенного объекта, то есть инициализацией внедренного объекта. Вместо назначения нового значения полю или свойства назначения в инициализаторе вложенных объектов рассматриваются как назначения членам поля или свойства
Ответ 2
Нет, это не ошибка.
Если вы хотите, чтобы он запускался, вы либо ставите new
до Bar
(как и вы для Foo перед инициализатором), либо создаете объект Bar в конструкторе Foo.
Инициализатор объекта по существу является просто синтаксическим сахаром.
Это:
var foo = new Foo
{
Bar = { Name = "Hello" }
};
Точно так же, как это:
var foo = new Foo();
foo.Bar.Name = "Hello";
Ответ 3
В инициализаторе объекта new
не требуется:
object-creation-expression:
new type ( argument-list(opt) ) object-or-collection-initializer(opt)
new type object-or-collection-initializer
object-or-collection-initializer:
object-initializer
collection-initializer
object-initializer:
{ member-initializer-list(opt) }
{ member-initializer-list , }
initializer-value:
expression
object-or-collection-initializer
Это последнее, что наиболее важно. Он представляет собой правую часть вашего синтаксиса property = value
. Это означает, что правая сторона может быть обычным выражением С# (с оператором new
) или другим инициализатором. В этом случае все, что вам нужно, это открывающие и закрывающие скобки.
Ответ 4
Если вы измените код на следующий эквивалент, вы также получите ошибку времени выполнения исключения NullReferenceException вместо ошибки/предупреждения времени компиляции.
static void Main(string[] args) {
Foo foo2 = new Foo();
foo2.Bar.Name = "test";
}
Эффект тот же, Bar никогда не инициализируется должным образом. Теперь, с точки зрения авторов компилятора, чрезвычайно сложно определить во всех случаях, правильно ли была инициализирована панель перед использованием.
Ответ 5
...
Bar = { Name = "Hello"}
...
означает: Foo.Bar.Name="Hello"
не: {Foo.Bar=new Bar(); Foo.Bar.Name="Hello";}
Это будет компилироваться и не будет вызывать никаких исключений, поэтому это не ошибка, вы просто инициализируете неиспользуемый объект:
class Bar
{
public string Name;
}
class Foo
{
private Bar _bar = new Bar();
public Bar Bar
{
get { return _bar; }
set { _bar = value; }
}
}
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo
{
Bar = { Name = "Hello"}
};
}
}
Ответ 6
Bar
является свойством Foo
, поэтому он позволяет вам получить к нему доступ и назначить свойство имени во время компиляции, но во время выполнения он проверяет действительный экземпляр Bar
, который отсутствует, выбрасывая исключение нулевой ссылки, это будет в случае любой версии С#.
Ответ 7
Я создаю рабочий образец .
Легко, только добавьте "новый Bar()" , он отлично работает
class Bar
{
public string Name { get; set; }
}
class Foo
{
public Bar Bar { get; set; }
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo
{
Bar = new Bar() { Name = "Hello" }
};
Console.WriteLine(foo.Bar.Name);
Console.ReadLine();
}
}