C#中带空值检查的init属性访问器及消除可空分析警告
在C#可空引用类型中实现带输入验证的init访问器(无CS8618警告)
问题背景
启用可空引用类型的C#项目中,给属性添加init访问器并做输入验证(比如空值检查)时会遇到两难:自动属性的init无法嵌入验证逻辑;改用私有 backing field 后,编译器会抛出CS8618警告(非可空字段未初始化),但又不想通过编译指令抑制警告或使用! null原谅运算符。
解决方案
方法一:通过构造函数初始化字段(兼容C# 9+)
显式定义构造函数,通过给属性赋值间接初始化backing field,从根源避免未初始化警告,同时保留init访问器的验证逻辑:
public class User { private string _username; public string Username { get => _username; init { _username = value ?? throw new ArgumentNullException(nameof(value), "用户名不能为空"); } } // 带参构造函数强制初始化属性 public User(string username) { Username = username; } // 若需要无参构造,可结合C# 11的required属性 public User() { } }
如果使用C# 11及以上版本,给Username属性添加required修饰符,即使有无参构造,编译器也会强制调用方在对象初始化时设置该属性,确保字段被正确初始化。
方法二:使用MemberNotNull特性(兼容C# 8+)
通过[MemberNotNull]特性告诉编译器,init访问器执行后会确保backing field非空,直接消除CS8618警告:
using System.Diagnostics.CodeAnalysis; public class Product { private string _productName; public string ProductName { get => _productName; [MemberNotNull(nameof(_productName))] init { _productName = value ?? throw new ArgumentNullException(nameof(value), "产品名称不能为空"); } } // 无参构造也不会触发警告 public Product() { } }
这个特性明确告知编译器,执行init访问器后_productName字段一定处于非空状态,无需额外初始化代码。
内容的提问来源于stack exchange,提问作者SENya
相关产品推荐
相关产品推荐

