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

时间:2010-10-01 14:19:51

标签: 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)
    {
        var foo = new Foo
                      {
                          Bar = { Name = "Hello" }
                      };
    }
}

这是一个已知的错误吗?

7 个答案:

答案 0 :(得分:41)

为什么你认为它不能编译?它是嵌套对象初始化器语法,客户端代码负责为初始化提供有效值。

来自文档:

C#规范7.5.10.2“对象初始化程序”

  

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

答案 1 :(得分:16)

不,这不是错误。

如果你希望它运行,你可以在new之前加Bar(就像你在初始化程序之前为Foo做的那样),或者在Foo的构造函数中创建Bar对象。

对象初始化器基本上只是语法糖。

此:

var foo = new Foo
            {
                Bar = { Name = "Hello" }
            };

与此完全相同:

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

答案 2 :(得分: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语法的右侧。这意味着右侧可以是正常的c#表达式(使用new运算符)另一个初始化程序。在这种情况下,您只需要打开和关闭括号。

答案 3 :(得分:2)

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

static void Main(string[] args) {
    Foo foo2 = new Foo();
    foo2.Bar.Name = "test";
}

效果相同,Bar从未正确初始化。现在,从编译器编写者的角度来看,在所有情况下都很难确定Bar在使用之前是否已正确初始化。

答案 4 :(得分:2)

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

答案 5 :(得分:1)

BarFoo的属性,因此它允许您在编译时访问它并分配名称属性,但在运行时它会检查{{1}的有效实例这不存在所以抛出空引用异常,任何C#版本就是这种情况。

答案 6 :(得分:0)

我创建了一个工作样本

很简单,只需添加一个“新栏()”一个正常工作


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();
    }
}