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

Это ошибка в компиляторе С# 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" }
                      };
    }
}

Является ли это известной ошибкой?

4b9b3361

Ответ 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();
    }
}