为何使用集合初始化语法时会调用Dictionary属性的Getter?
为什么第二种初始化方式会抛出NullReferenceException?
这个问题的核心在于你混淆了对象属性赋值和集合初始化器这两种C#语法糖的底层逻辑,咱们一步步拆解:
两种写法的本质区别
第一种(正常运行的写法)
var dataRow = new FlatDataRow { Id = 12, Fields = new Dictionary<string, object>() { { "skills", skills} } };
这里你是直接给Fields属性赋值:先创建一个全新的Dictionary<string, object>实例,用集合初始化器给这个新实例添加"skills"键值对,最后把整个实例赋值给Fields属性。整个过程完全不会用到Fields原本的Getter——毕竟你是直接覆盖它的默认null值。
第二种(抛出异常的写法)
var dataRow = new FlatDataRow { Id = 12, Fields = { { "skills", skills} } };
这里的{ { "skills", skills} }是集合初始化器语法,它的执行逻辑和赋值完全不同:
- 首先调用
dataRow.Fields的Getter,试图获取当前Fields的实例(但因为Fields是get;set;属性,默认值是null) - 接着尝试对这个
null实例调用Add("skills", skills)方法 - 因为实例是
null,自然就抛出了NullReferenceException
什么时候第二种写法能正常工作?
集合初始化器语法的前提是:目标集合已经被初始化(不为null)。如果你的FlatDataRow在构造函数里提前初始化了Fields,那第二种写法就没问题:
public class FlatDataRow { public int Id { get; set; } public Dictionary<string, object> Fields { get; set; } public FlatDataRow() { // 构造函数里提前初始化集合 Fields = new Dictionary<string, object>(); } }
此时调用dataRow.Fields的Getter会拿到一个有效的Dictionary实例,集合初始化器就能正常调用Add方法添加元素了。
一句话总结
第一种写法是给属性赋值新的集合实例,第二种写法是对已有集合实例添加元素——C#的语法让它们看起来相似,但底层逻辑天差地别,这就是为什么后者会抛出空引用异常。
内容的提问来源于stack exchange,提问作者Ole Albers
相关产品推荐
相关产品推荐

