.NET 6.0构造函数调用Init方法触发CS8618警告的正确解决方案
.NET 6 中抽离构造函数初始化逻辑触发CS8618警告的合规解决方案
警告触发原因
C# 可空引用类型的编译器流分析默认不会跟踪构造函数调用的普通实例方法内的字段赋值状态,哪怕构造函数确实调用了为非空字段赋值的Init方法,编译器也无法确认该方法会保证字段非空,因此抛出CS8618警告。
最优解决方案(无侵入、符合官方规范)
使用.NET 内置的MemberNotNull特性标记初始化方法,明确告知编译器:该方法执行完成后,指定的非空成员一定会被赋值为非空值。这个方案不需要将字段改为可空类型,不需要用#pragma屏蔽警告,也不会破坏类的非空契约。
实现代码
using System.Diagnostics.CodeAnalysis; class ClassA { public string Name; public ClassA(int i) { Init(i.ToString()); } public ClassA(string s) { Init(s); } // 标记该方法初始化完成后Name字段一定非空 [MemberNotNull(nameof(Name))] private void Init(string id) { Name = id; // 原有其他初始化逻辑无需任何改动 //lots of other stuff happening in this method } }
方案说明
- 如果
Init方法内同时初始化多个非空字段/属性,直接在特性参数中追加对应的成员名即可,例:[MemberNotNull(nameof(Name), nameof(OtherField), nameof(ThirdProperty))] - 该特性仅作为编译器可空分析的元数据,不会产生任何运行时开销,不影响原有代码执行逻辑
- 所有调用
ClassA的代码依然可以认定Name为非空字符串,不需要额外做null校验,完全保留非空类型约束 - .NET 6 已内置该特性,无需额外安装依赖;如果是更低版本框架缺失该特性,可以自行在项目中定义同名同命名空间的特性,编译器可正常识别,自定义特性代码如下:
namespace System.Diagnostics.CodeAnalysis; [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullAttribute : Attribute { public MemberNotNullAttribute(string member) { Members = new[] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } public string[] Members { get; } }
内容的提问来源于stack exchange,提问作者scantrell
相关产品推荐
相关产品推荐

