SuperAPI AI 工具集

csharp-nullable-types

编程与开发

查看项目

更新于 10-16 02:22

技能介绍

用途

该技能用于在 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 参数、返回值与成员标注空值语义。
  • 使用空条件、空合并、模式匹配等方式编写空安全代码。
  • 将历史代码库逐步迁移到可空上下文。

限制

资料未说明该技能的安装命令、依赖、支持平台、收费方式或性能效果,这些信息暂未提供。