这是C#4.0编译器中的错误吗?

这是C#4.0编译器中的错误吗?,c#,compiler-construction,object-initializers,C#,Compiler Construction,Object Initializers,这段代码编译成功,但我认为它应该无法编译。此外,当您运行它时,您会得到一个NullReferenceException。缺少的代码是Bar属性初始化中的“新条” class Bar { public string Name { get; set; } } class Foo { public Bar Bar { get; set; } } class Program { static void Main(string[] args) { va

这段代码编译成功,但我认为它应该无法编译。此外,当您运行它时,您会得到一个
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" }
                      };
    }
}

这是一个已知的bug吗?

为什么您认为它应该无法编译?它是嵌套对象初始值设定项语法,客户端代码负责为初始化提供有效值

从文件中:

C#规范7.5.10.2“对象初始值设定项”

在等号后指定对象初始值设定项的成员初始值设定项是嵌套对象初始值设定项,即嵌入式对象的初始化。嵌套对象初始值设定项中的指定将被视为对字段或属性成员的指定,而不是为字段或属性指定新值


对象初始值设定项中不需要新的

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
语法的右侧。这意味着右侧可以是一个正常的c#表达式(使用
new
运算符)或另一个初始化器。在这种情况下,您只需要开始和结束大括号。

Bar
Foo
的一个属性,因此它允许您在编译时访问它并分配一个name属性,但在运行时它会检查
Bar
的有效实例,该实例不存在,因此引发空引用异常,任何C版本都是如此。

不,这不是一个bug

如果您想让它运行,您可以在
Bar
之前放置一个
new
(就像您在初始化之前对Foo所做的那样),或者在Foo的构造函数中创建Bar对象

对象初始值设定项本质上只是语法糖

这:

与此完全相同:

var foo = new Foo();
foo.Bar.Name = "Hello"; 

如果将代码更改为以下等效代码,还将获得NullReferenceException的运行时错误,而不是编译时错误/警告

static void Main(string[] args) {
    Foo foo2 = new Foo();
    foo2.Bar.Name = "test";
}
效果是一样的,Bar从未正确初始化。现在,从编译器编写者的角度来看,在所有情况下都很难确定Bar在使用之前是否正确初始化

...
 Bar = { Name = "Hello"}
...
意思是:
Foo.Bar.Name=“Hello”
不是:
{Foo.Bar=newbar();Foo.Bar.Name=“Hello”}

这将编译并且不会引发任何异常,因此这不是一个bug,您只是在初始化一个不存在的对象:

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"}
  };
 }
}

我创建了一个工作样本

这很简单,只需添加一个“新条()”就可以了



为什么你认为它不能编译?我不会认为这是一个编译器错误,因为这是不可能的work@Maxm007:你怎么知道它永远不会起作用?编译器不能提供错误,除非编译器有确定何时提供错误的算法。你认为哪种情况应该是错误的?哇,我不知道!非常感谢。对这个问题的描述很好。是的,理解了新的不是必需的,但是bar的类型在哪里?它是推断出来的,因为类型是根据正在初始化的属性已知的。所以如果它推断它是bar,然后假设它是新的bar,为什么它抛出nullrefexception。啊,明白了。如果你预先初始化酒吧将工作。我不知道您可以对现有实例使用初始值设定项
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"}
  };
 }
}
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();
    }
}