给定的
public class SomeClassWithAList
{
public List<int> list { get; set; }
}
[Fact]
public void InitListInsideModel()
{
var cashthing = new SomeClassWithAList { list = { 4 } };
}
Run Code Online (Sandbox Code Playgroud)
我的问题是它看起来InitListInsideModel是一个有效的代码,但这段代码实际上不会执行。
System.NullReferenceException:未将对象引用设置为对象的实例。
这里发生了什么?我不明白什么基本概念?这是编译器错误吗?为什么 IntelliSense 没有警告我我不能以这种方式实例化列表?
TLDR
如您所知,修复方法是以一种或另一种方式初始化集合
public List<int> list { get; set; } = new List<T>();
// or
var cashthing = new SomeClassWithAList
{
list = new List<int>(){ 4 }
};
Run Code Online (Sandbox Code Playgroud)
至于为什么您可以这样做而不会收到警告?嗯……这是一个有趣的问题。
乍一看,它看起来像一个roslyn错误,它允许在对象初始化程序中的集合上使用无效的数组初始化程序语法。
然而,它实际上是设计使然。语法的作用是使用集合方法的分辨率添加序列。为此,需要初始化集合!Add
你每天学习新的东西
下列
var cashthing = new SomeClassWithAList
{
list = { 4 }
};
Run Code Online (Sandbox Code Playgroud)
new SomeClassWithAList().list.Add(4);
Run Code Online (Sandbox Code Playgroud)
IMO,静态分析应该能够对此发出警告(尤其是对于可为空类型),它也应该在Object and Collection Initializers (C# Programming Guide) 中有详细记录。
我能找到合适文档的唯一地方是C# 语言规范
强调我的
7.6.10.2 对象初始值设定项
...
在等号后指定集合初始值设定项的成员初始值设定项是嵌入集合的初始化。不是将新集合分配给字段或属性,而是将初始值设定项中给出的元素添加到字段或属性引用的集合中。字段或属性必须是满足 §7.6.10.3 中指定要求的集合类型。
所以这个功能的正确用法是确保你的集合是自动初始化的
public List<int> list { get; set; } = new List<T>();
Run Code Online (Sandbox Code Playgroud)
其他资源
在挖掘了更多之后,我发现了以下内容
GitHub 问题讨论了这种确切情况
想要在文档中添加更多细节以阐明语言功能的 GitHub 问题