C#中字典使用隐式集合初始化为何引发运行时NullReferenceException?
Why does the collection initializer throw NullReferenceException without explicit
new? 这个问题其实是C#集合初始化器的典型陷阱,咱们一步步拆解清楚原因:
核心原理:集合初始化器的工作逻辑
当你在对象初始化器里写Attributes = { {"businessType", "0"} }时,编译器并没有自动帮你创建新的Dictionary实例。它生成的代码逻辑是:
- 先创建
UpdateMerchantRequestModel的实例 - 调用该实例
Attributes属性的Add方法,把键值对插入集合
但你的UpdateMerchantRequestModel类里仅定义了public Dictionary<string, string> Attributes { get; set; },没有在构造函数中初始化这个属性——默认情况下Attributes是null。此时调用null.Add(...),自然会抛出NullReferenceException。
两种写法的编译器代码对比
错误写法(你最初的代码)
await client.UpdateMerchantAttributes(new UpdateMerchantRequestModel { Attributes = { {"businessType", "0"} } });
编译器生成的等价简化代码:
var model = new UpdateMerchantRequestModel(); // Attributes此时为null,调用Add直接触发空引用 model.Attributes.Add("businessType", "0"); await client.UpdateMerchantAttributes(model);
正确写法(显式声明Dictionary)
await client.UpdateMerchantAttributes(new UpdateMerchantRequestModel { Attributes = new Dictionary<string, string> { {"businessType", "0"} } });
编译器生成的等价简化代码:
var model = new UpdateMerchantRequestModel(); // 先创建字典实例并赋值给Attributes model.Attributes = new Dictionary<string, string>(); // 此时Attributes有实例,调用Add正常执行 model.Attributes.Add("businessType", "0"); await client.UpdateMerchantAttributes(model);
为什么编译器不报错?
编译器无法提前判断Attributes在对象初始化时是否已经被初始化。比如如果你的UpdateMerchantRequestModel构造函数里已经给Attributes赋值:
public class UpdateMerchantRequestModel { public Dictionary<string, string> Attributes { get; set; } public UpdateMerchantRequestModel() { // 构造函数中初始化集合 Attributes = new Dictionary<string, string>(); } }
那你最初的写法就是完全合法的,编译器不会有任何问题。因此编译器只能假设该属性已有实例,把空引用检查留到运行时。
避免陷阱的两种方法
- 在类构造函数中初始化集合属性:确保
Attributes在对象创建时就不为null,之后使用集合初始化器就安全了。 - 显式创建集合实例:像你后来做的那样,直接在对象初始化器里
new出Dictionary,再用集合初始化器添加元素。
内容的提问来源于stack exchange,提问作者Jansky
相关产品推荐
相关产品推荐

