对象中列表属性初始化的最佳实践是什么?
对象中列表属性初始化位置的取舍
这确实是日常开发中很常见的一个风格分歧,我来聊聊两种方式的优劣和适用场景:
一、提前初始化(构造函数/属性初始化器)的优势
- 彻底避免空引用异常:调用方不用每次操作列表前都写
if (Words == null)的判断,直接调用Words.Add()或者遍历都不会报错,大幅降低了低级bug的概率。 - 符合「最小惊讶原则」:对象实例化后,属性就处于可用状态,调用方不需要关心内部的初始化逻辑,学习和使用成本更低。
- 代码更简洁优雅:C# 6+支持的属性初始化器写法
public List<string> Words { get; set; } = new List<string>();一行就能搞定,比在构造函数里单独写初始化代码清爽很多,可读性也更强。
二、「每次访问前检查null」的适用场景
这种写法并非一无是处,只在少数特定场景下有意义:
- 初始化成本极高且极少被用到:比如这个列表需要加载大量数据、依赖外部资源,而90%的业务流程都不会触发对它的访问。不过要注意,空List的内存占用几乎可以忽略,普通场景下这点优势可以忽略不计。
- 需要用null表达特殊语义:比如用
null表示「数据未加载」,用空List表示「确实没有数据」,这种语义区分需要团队提前统一约定,否则很容易造成混淆,反而引发bug。
三、我的建议
- 绝大多数场景优先提前初始化:空引用异常是开发中最常见的bug类型之一,提前初始化能从根源上消除这种风险,代码的健壮性和可维护性都会更好。属性初始化器是当前C#推荐的写法,值得优先采用。
- 如果确实需要延迟初始化,别手动判空,用
Lazy<T>更优雅:
这样既实现了「用到才初始化」的效果,又不用每次访问都写重复的判空逻辑,代码更简洁,也避免了手动判空可能出现的疏漏。private readonly Lazy<List<string>> _lazyWords = new Lazy<List<string>>(() => new List<string>()); public List<string> Words => _lazyWords.Value; - 遵循团队编码规范:如果团队已经有统一的约定,优先按规范来,保持代码风格一致比纠结哪种写法更优更重要。
内容的提问来源于stack exchange,提问作者KeizerHarm
相关产品推荐
相关产品推荐

