为什么这个错误的对象初始化大括号甚至编译?

时间:2018-03-05 14:33:37

标签: c# curly-braces object-initializers

Whille为WPF / MVVM项目的集合创建了一些虚拟数据,我生成了以下错误代码,编译得很好,但在运行时抛出异常。

有一个嵌套的数据对象结构,我错误地只用花括号进行实例化(看起来像编写JavaScript确实会对大脑造成永久性伤害)。

using System.Collections.ObjectModel;

namespace testapp
{
    class Program
    {
        static void Main(string[] args)
        {
            var collection = new ObservableCollection<TopLevelDataObject>();
            collection.Add(new TopLevelDataObject{Nested = {Bar = 5}});         // NullReferenceException
        }

        class TopLevelDataObject
        {
            public NestedDataObject Nested { get; set; }
            public string Foo { get; set; }
        }

        class NestedDataObject
        {
            public double Bar { get; set; }
        }
    }
}

为什么要编译?

如果我创建一个匿名类型,如Nested = new {Bar = 5},我会在编译期间收到错误消息(因此失败):

Cannot implicitly convert type '<anonymous type: int Bar>' to 'testapp.Program.NestedDataObject'

为什么在省略new运算符时没有出现这样的错误?

它甚至为我提供了属性的代码提示: click to see the image, for I do not have enough rep to embed it yet

我的猜测是{Bar = 5}只是一个代码块,它本身就是一个有效的东西。 但为什么将代码块分配给任何东西(在这种情况下,Nested属性)是有效的?

2 个答案:

答案 0 :(得分:5)

  

为什么要编译?

因为编译代码时,它只被编译为一组赋值操作。它并非都是您创建的新实例。

如果您从构造函数构造Nested的新实例,则可以为Nested.Bar指定一个值。

public NestedDataObject Nested { get; set; }更改为此以查看其工作原理:

public NestedDataObject Nested { get; } = new NestedDataObject();

(注意,在上面的代码中,你永远不能在构造函数之外的Nested赋值!)

答案 1 :(得分:2)

  

为什么要编译?

因为def update(self): self.x=games.mouse.x self.y=games.mouse.y 与:

相同
var x = new SomeType{Property = value};

实际上,我们甚至可以让var x = new SomeType(); x.Property = value; ()甚至var x = new SomeType(){Property = value};组合将参数传递给构造函数并设置值。

因此你可以看到总是有一个被调用的构造函数,如果你省略了那个使它显式的括号,它总是那个nullary(无参数)构造函数。

同时,没有显式构造函数的类型总是有一个公共的无效构造函数(&#34;默认构造函数&#34;)。

因此var x = new SomeType(argument){Property = value};与:

相同
new TopLevelDataObject{Nested = {Bar = 5}}

因为var temp = new TopLevelDataObject(); temp.Nested.Bar = 5; // NRE on temp.Nested 可以有一个构造函数来设置`Nestedt,那么你所拥有的代码可以工作,所以它应该编译。当然,因为没有拥有这样的构造函数,所以它不起作用。

(请注意,初始化程序与匿名类型的操作完全相同,在这种情况下,它会被重写以调用隐藏的构造函数,因此即使初始化程序不能以只读方式使用,也允许这些属性为只读属性非匿名类型的属性。语法允许它们看起来相同,因此很容易理解为相似但结果却不一样。)