用途
该技能用于在 C# 代码中实现空安全,主要面向 C# 8+ 的可空引用类型(Nullable Reference Types)。适用场景包括:启用编译期空值检查、编写空安全模式、以及将已有代码迁移到可空上下文。
主要能力
可空引用类型(C# 8+)
可空引用类型通过区分可空引用类型与非可空引用类型,提供编译期空安全检查。
启用可空上下文的方式:
- 项目级:在 .csproj 中设置
<PropertyGroup><Nullable>enable</Nullable></PropertyGroup> - 文件级指令:
#nullable enable - 对旧代码关闭:
#nullable disable - 恢复项目默认:
#nullable restore
示例中,非可空属性必须初始化(如 public string Name { get; set; } = string.Empty;),可空属性用 ? 标注(如 public string? MiddleName { get; set; }),非可空且需在构造函数中赋值的属性如 Email 由构造函数设置。
非可空与可空引用示例中,非可空参数与返回类型如 FormatName(string firstName, string lastName) 返回 string;可空参数如 FormatNameWithMiddle(string firstName, string? middleName, string lastName) 在内部判断 middleName != null;可空返回类型如 FindUserEmail(int userId) 返回 string?,并使用 user?.Email。若直接对可空参数调用 name.ToUpper() 会产生 CS8602 警告,修复方式是先做 null 检查并抛出 ArgumentNullException。
可空值类型
值类型可用 Nullable<T> 或 ? 语法变为可空,例如 int? Age、DateTime? BirthDate、decimal? Salary、bool? IsActive,其中 int? 等价于 Nullable<int>。相关成员包括 HasValue、Value、GetValueOrDefault()(默认值 0)、GetValueOrDefault(42)(指定默认值 42),以及空合并运算符 value ?? 100。对可空值类型执行算术运算时,a + b 得到 15,而 a + c(c 为 null)结果为 null;比较运算 a == b 得到 false,a == c 结果为 null(既非 true 也非 false)。三值布尔逻辑中,true & null 为 null,false & null 为 false,true | null 为 true,false | null 为 null。
空安全注解
使用 System.Diagnostics.CodeAnalysis 中的特性向编译器提供额外空安全信息:
[NotNull]:方法正常返回时参数不为 null,如ProcessUser([NotNull] User? user)。[MaybeNull]:即使类型为非可空,返回值仍可能为 null,常配合[return: MaybeNull]用于泛型方法GetValueOrDefault<T>。[NotNullWhen(true)]:当方法返回指定的布尔值时参数不为 null,用于TryGetUser(int id, [NotNullWhen(true)] out User? user)。[NotNullIfNotNull(nameof(value))]:若参数不为 null 则返回值不为 null。[DoesNotReturn]:方法永不正常返回,如ThrowError。[MemberNotNull(nameof(_name), nameof(_email))]:告知编译器这些成员已在方法中初始化,可用于构造函数调用的Initialize与Reset方法。
Null-forgiving 运算符
! 运算符在开发者确信不为 null 时抑制可空警告,如 _currentUser!.Name。资料指出应谨慎、少量使用;更推荐显式检查并抛出异常(如 InvalidOperationException)。并给出反面示例:对可空输入直接 input!.ToUpper() 会在输入为 null 时崩溃;_repository.Find(id)! 可能实际为 null,更安全写法是 ?? throw new KeyNotFoundException(...)。
空条件运算符
?. 与 ?[] 提供安全导航:user?.Name 在 user 为 null 时返回 null;可链式使用 user?.Address?.City;可做索引访问 user?.Name?[0];可与方法调用组合 user?.CalculateAge();也可用于数组与集合,如 numbers?[0]、numbers?.Max()、users?["key"];对委托与事件可写 callback?.Invoke()、handler?.Invoke(this, EventArgs.Empty)。
空合并运算符
?? 提供默认值:name ?? "Unknown",可链式回退,可与空条件组合 user?.Name?.Length ?? 0。??= 用于空合并赋值,典型用途是延迟初始化 _cachedUser ??= LoadUser(id);、集合初始化 _items ??= new List<string>();,以及仅当为 null 时赋值 user.MiddleName ??= "N/A";。
模式匹配中的 null(C# 9+)
支持 obj is null、obj is not null、类型模式 obj is string s、属性模式 obj is User { Name: not null } user,以及 switch 表达式返回描述文本,如 user switch { null => "No user", { Name: null } => "User without name", { Name: var name } => $"User: {name}" }。递归模式示例中对 order 的 Customer、Customer.Address、Customer.Address.City 逐级判断。
迁移策略
增量迁移步骤:一是在 .csproj 中启用可空并将可空警告视为错误:<Nullable>enable</Nullable> 与 <WarningsAsErrors>nullable</WarningsAsErrors>;二是按文件迁移,使用 #nullable enable 并修复该文件所有警告;三是对历史代码使用 #nullable disable 暂时关闭,再用 #nullable restore 恢复。迁移模式示例包括:将默认可空改为显式可空;把可选参数改成显式可空并可设默认值 string? format = null 配合 format ??= "json";;以及使用可空返回类型表达可能为 null 的查找结果。
适用场景
- 在 C# 8+ 项目中启用并编写可空引用类型代码。
- 为 API 参数、返回值与成员标注空值语义。
- 使用空条件、空合并、模式匹配等方式编写空安全代码。
- 将历史代码库逐步迁移到可空上下文。
限制
资料未说明该技能的安装命令、依赖、支持平台、收费方式或性能效果,这些信息暂未提供。