Visual Studio 2015 缺少新关键字 - 没有编译器错误

Visual Studio 2015 missing new keyword - no compiler error

当我犯了一个愚蠢的错误时,我正在开发我们的一个新应用程序......我忘了在对象初始化程序中写:“new ClassName”。 奇怪的是 VS 只是编译了代码……没有任何错误或警告。 (我用过VS 2015, .Net 4.5.2)

我的代码:

var target = new MyClass
{
    MyValues = new List<MyOtherClass>
    {
        new MyOtherClass
        {
            Start = new DateTimeValue
            {
                DateTime = new DateTime(2015, 08, 23)
            },
            End = {
                DateTime = new DateTime(2015, 08, 23)
            }
        }
    }
};

(开始和结束都是 DateTimeValue 类型)

当我启动应用程序时,这段代码抛出了 NullReferenceException。 (添加“new DateTimeValue”解决了这个问题)。 为什么编译器没有错误?

因为这是有效的语法。

它将大致翻译成以下内容:

var target = new MyClass();
target.MyValues = new List<MyOtherClass>();

var i = new MyOtherClass();

i.Start = new DateTimeValue();
i.Start.DateTime = new DateTime(2015, 08, 23);

i.End.DateTime = new DateTime(2015, 08, 23);

target.MyValues.Add(i);

除了属性只设置一次,并且永远不会被编译器读取。这将需要使用额外的临时变量(就像 Jon 在他的回答中所做的那样),但为了简单起见,我没有费心在这里写它们。

此语法对于 MyOtherClass 在其构造函数中实例化 End 属性 的情况很有用。当 属性 为只读时也可以使用。

完全没有问题。它使用 End 的对象初始值设定项,它使用现有值设置属性,而不是将 new 值分配给 End。您的代码相当于:

var tmp0 = new MyClass();
var tmp1 = new List<MyOtherClass>();
var tmp2 = new MyOtherClass();
var tmp3 = new DateTimeValue();
tmp3.DateTime = new DateTime(2015, 8, 23);
// Note the assignment to Start here
tmp2.Start = tmp3;

// No assignment to End -
// it's calling the End "getter" and then the DateTime "setter" on the result
tmp2.End.DateTime = new DateTime(2015, 8, 23);
tmp1.Add(tmp2);
tmp0.MyValues = tmp1;
var target = tmp0;

来自 C# 5 规范,第 7.6.10.2 节:

A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property.

这正是您在这里所做的 - { DateTime = ... } 部分是一个对象初始值设定项。