16

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

这是一个已知的错误?

4

7 回答 7

41

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

从文档中:

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

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

于 2010-10-01T14:23:06.923 回答
16

不,这不是错误。

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

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

这个:

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

与此完全相同:

var foo = new Foo();
foo.Bar.Name = "Hello"; 
于 2010-10-01T14:26:17.650 回答
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运算符)另一个初始化程序。在这种情况下,您只需要打开和关闭大括号。

于 2010-10-01T14:24:18.170 回答
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"}
  };
 }
}
于 2010-10-01T14:47:46.257 回答
2

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

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

效果是一样的,Bar 永远不会被正确初始化。现在,从编译器编写者的角度来看,在所有情况下都很难确定 Bar 在使用之前是否已正确初始化。

于 2010-10-01T14:33:47.397 回答
1

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

于 2010-10-01T14:25:04.780 回答
0

我创建了一个工作示例

它很简单,只需添加一个“new 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();
    }
}
于 2010-10-05T12:02:13.740 回答