📋 NRT 速查 Nullable Reference Types
C# 8 引入 · 编译时静态分析 · 无运行时开销 · 📖 完整课程
开启方式
| 方式 | 写法 | 作用范围 |
| 项目级 | <Nullable>enable</Nullable> in .csproj | 整个项目 |
| 文件级 | #nullable enable 在文件顶部 | 当前文件 |
| 局部关闭 | #nullable disable | 从该行到文件尾(或 restore) |
| 恢复项目设置 | #nullable restore | 回到 .csproj 的设定 |
核心语法 / 四个角色
| 写法 | 名称 | 含义 | 编译器行为 |
string name |
非 null 引用 |
"我承诺这不是 null" |
若赋值 null → ⚠️ 警告 |
string? name |
可空引用 |
"这可能是 null" |
若直接访问成员 → ⚠️ 警告 |
name! |
空包容操作符Null-forgiving |
"我断言它不是 null——闭嘴" |
抑制该表达式上的所有 NRT 警告 |
name ?? "default" |
空合并Null-coalescing |
左边是 null 时取右边 |
结果被追踪为 not-null |
x ??= y |
空合并赋值 (C# 8) |
若 x 为 null 则赋值 y |
短路求值 |
流分析Flow Analysis —— 编译器如何追踪
编译器追踪变量在每条执行路径上的 null 状态:MaybeNull / NotNull。
✅ 编译器放行(自动推断 NotNull)
string? name = GetName();
// null 检查后
if (name != null)
Use(name.Length); // ✅ NotNull
// throw 守卫后
if (name == null)
throw new ArgumentNullException();
Use(name.Length); // ✅ NotNull
// null-coalescing 后
var s = name ?? "";
Use(s.Length); // ✅ NotNull
⚠️ 编译器警告(无法证明 NotNull)
string? name = GetName();
Use(name.Length); // ⚠️ MaybeNull
// 跨方法调用后状态重置
if (name != null)
{
DoSomething(); // 编译器不跨方法追踪
Use(name.Length); // ✅ 仍在 if 块内
}
// 赋值 T? → T
string? a = null;
string b = a; // ⚠️ 警告
Null-state 分析 Attribute
| Attribute | 用途 |
[NotNullWhen(true)] | TryXxx 模式:返回 true 时 out 参数为 NotNull |
[NotNullWhen(false)] | 返回 false 时 out 参数为 NotNull |
[MaybeNullWhen(true)] | 返回 true 时 out 参数可能为 null |
[MemberNotNull(nameof(field))] | 方法调用后指定字段不为 null(如 OnInit) |
public bool TryGetUser(int id,
[NotNullWhen(true)] out User? user)
{
user = _users.FirstOrDefault(u => u.Id == id);
return user != null;
}
// 调用侧:if (TryGetUser(42, out var u)) → u 自动 NotNull
常见模式
DI 构造注入
// 构造函数中赋值 → 编译器追踪到 → 不警告
public class UserService
{
private ILogger _logger;
public UserService(ILogger logger) { _logger = logger; }
}
EF Core 导航属性
public Customer Customer { get; set; } = null!;
// null! = 给初始值 null + ! 让编译器别管(EF 反射填充)
NRT 是编译时检查,不是运行时保证。JIT 不插入 null 检查。通过反射调用、或未开 nullable 的代码仍可传入 null。BCL 公开 API 仍保留显式 ThrowIfNull(.NET 6+)。
迁移策略Migration
- 开
warnings 先不报错:<Nullable>warnings</Nullable>
- 逐文件加
#nullable enable,修完一个再下一个
- 公共 API 优先 → internal 代码 → 测试项目
- DI / EF Core / 反射场景善用
null!
相关速查