如何通过方法而非构造函数初始化非空属性并实现编译强制检查?
问题描述
在我们的架构中,存在一个会在调用其他任何方法前被执行的方法,用于初始化对象构造时无法获取的引用。
以下是这类类的示例代码:
#nullable enable public class MyClass { private MyReference _reference; // 此处触发警告 public MyClass() { } public void Activate() { _reference = new MyReference(); } }
目前私有字段因未在构造函数中初始化触发了警告(合理)。已尝试两种方案,但都不尽如人意:
- 将字段设为可空,但每次访问该字段都必须进行空检查;
- 将所有在
Activate中初始化的字段标记为= null!,虽消除了错误,但无法强制字段被实际初始化。
问题:是否存在某种属性或方法,能让上述示例正常工作,即当类的字段在构造函数外初始化时,仍能通过编译警告实现强制初始化?
解决方案
1. 使用[MemberNotNull]属性(C# 8.0+)
给Activate方法添加[MemberNotNull]属性,明确告知编译器:调用该方法后指定的字段将被初始化。搭配null!抑制初始的未初始化警告,同时编译器会检查字段访问是否在Activate调用之后,若提前访问则触发警告。
示例代码:
#nullable enable using System.Diagnostics.CodeAnalysis; public class MyClass { private MyReference _reference = null!; // 抑制初始警告 public MyClass() { } [MemberNotNull(nameof(_reference))] public void Activate() { _reference = new MyReference(); } public void DoSomething() { // 若未先调用Activate,此处访问_reference会触发CS8602(可能的空引用)警告 _reference.DoWork(); } }
2. 工厂模式强制初始化
将构造函数设为私有,通过静态工厂方法创建实例并自动调用Activate,确保外部无法获取未完成初始化的对象,从根源避免未初始化的问题。
示例代码:
#nullable enable public class MyClass { private MyReference _reference; private MyClass() { } private void Activate() { _reference = new MyReference(); } public static MyClass Create() { var instance = new MyClass(); instance.Activate(); return instance; } public void DoSomething() { _reference.DoWork(); // 无警告,因为Create已确保初始化 } }
3. 延迟初始化(Lazy<T>)
将字段声明为Lazy<MyReference>,在构造函数中初始化Lazy的逻辑,然后在Activate中主动触发初始化(调用Value属性)。这种方式既保证字段不会为空,又能控制初始化时机。
示例代码:
#nullable enable public class MyClass { private readonly Lazy<MyReference> _lazyReference; public MyClass() { _lazyReference = new Lazy<MyReference>(() => new MyReference()); } public void Activate() { // 主动触发初始化,确保后续访问时已就绪 _ = _lazyReference.Value; } public void DoSomething() { // 直接访问Value,无需空检查,Lazy确保已初始化 _lazyReference.Value.DoWork(); } }
内容的提问来源于stack exchange,提问作者Sander van 't Einde
相关产品推荐
相关产品推荐

