现象
抛出 System.NullReferenceException: Object reference not set to an instance of an object.;堆栈指向访问属性或调用方法的那一行;只在生产环境或配置变更后出现;项目未启用可空引用类型警告。
诊断
先启用可空分析,让编译器指出可能为空的流转路径:
dotnet build -p:Nullable=enable -p:WarningsAsErrors=nullable
dotnet test --logger "console;verbosity=detailed" 2>&1 | grep -A20 'NullReferenceException'
dotnet format analyzers --verify-no-changes --severity warn 2>&1 | head -40
堆栈中第一个业务代码帧就是解引用点,但空值可能来自更早的依赖注入失败、FirstOrDefault 无匹配或异步方法返回 null。重复出现的 CS8602 警告集中在某个类,通常意味着字段未初始化或构造函数路径遗漏。启动时若提示依赖无法解析,应检查 DI 注册,并在开发环境开启 ValidateOnBuild。
修复
在项目级启用可空引用类型,并把可空警告视为错误;公共入口用 ArgumentNullException.ThrowIfNull 校验,查询结果显式判断空值,集合与依赖在构造时初始化:
public OrderService(IOrderRepository repository)
{
_repository = repository
?? throw new ArgumentNullException(nameof(repository));
}
public decimal Total(Order order)
{
ArgumentNullException.ThrowIfNull(order);
return order.Lines.Sum(line => line.Price * line.Quantity);
}
不要用 null-forgiving 运算符 ! 压掉警告,那只是隐藏风险;也不要把所有属性都改成可空,那会让契约变得模糊。
验证
在可空警告视为错误的配置下重新构建,确认解引用处的警告已消失、流程可证明非空。运行覆盖失败路径的测试,再复现原生产场景,异常应不再出现,或变为明确指出参数名的 ArgumentNullException,后者说明边界校验已经生效。