接口集合成员在对象初始化期间的奇怪行为
本文关键字:成员 集合 对象 初始化 接口 | 更新日期: 2023-09-27 18:04:45
我在以下代码中遇到运行时NullReferenceException
异常:
public class Container
{
public IList<string> Items { get; set; }
}
class Program
{
static void Main(string[] args)
{
var container = new Container() { Items = {"Test"} };
}
}
这是合乎逻辑的,编译器不能创建接口实例,但我得到一个运行时异常,而不是编译时间。当我进一步研究这种行为时,我更加困惑了:
var container = new Container() { Items = {} }; //Legal, Items is null after initialization
var container = new Container() { Items = { "Test" } }; //Legal, throws exception
container.Items = {}; //Illegal doesn't compile
container.Items = {"Test"}; //Illegal doesn't compile
这是某种bug还是我没理解什么?我用的是。net framework 4.0
它编译,因为编译器不知道是List
已经在其他地方初始化。您可以通过在构造函数中添加初始化来使它工作:
public class Container
{
public IList<string> Items { get; set; }
public Container()
{
Items = new List<string>();
}
}
或更改属性以隐藏字段,该字段在创建类实例时初始化:
private IList<string> items = new List<string>();
public IList<string> Items
{
get { return items; }
set { items = value; }
}
那么,var container = new Container() { Items = { "Test" } };
工作得很好。
运行时对集合初始化组中的每个项调用.Add()
方法。当属性没有初始化为new List<string>
时,它的值是null
,这就是为什么会抛出NullReferenceException
。
对象和集合初始化式(c#编程指南)
通过使用集合初始化式,您不必指定多个在源代码中调用类的Add方法;编译器添加调用
您没有初始化List
var container = new Container() { Items = new List<string>() { "Test" } };
顺便说一下,下面是合法的,因为编译器没有任何问题(语法是正确的,等等)
var container = new Container() { Items = {} };
但是因为编译器不知道Items
列表没有被初始化(你没有在集合初始化器{}
中传递任何项),.Add
方法不会在List
上被调用,并且运行时不会知道Items
对象是空的
另一方面,下面的代码对编译器来说是合法的,但是它会在运行时抛出一个异常,因为你试图初始化传递一个项的列表(这对编译器来说是正确的,原因与上面解释的相同),所以当运行时调用.Add
方法时,它会抛出一个空引用异常,因为Items
还没有初始化
var container = new Container() { Items = { "Test" } };