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 = ... }
部分是一个对象初始值设定项。
当我犯了一个愚蠢的错误时,我正在开发我们的一个新应用程序......我忘了在对象初始化程序中写:“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 = ... }
部分是一个对象初始值设定项。