如何将NotNullWhen特性与自定义返回类型Outcome配合使用?
问题原因
[NotNullWhen(true)]特性的设计是绑定到返回值为bool的方法,它指示当方法返回指定布尔值时,对应的out参数不为null。你的方法返回的是自定义Outcome类型,即便该类型有隐式布尔转换,编译器也无法将对Outcome的布尔判断,与[NotNullWhen(true)]的触发条件关联起来,因此无法推断entity在成功分支下的非空性。
替代方案
方案1:改用泛型Outcome<T>封装结果
将实体直接嵌入Outcome对象中,替代out参数的使用,让编译器能通过IsSuccess属性推断结果的非空性:
首先定义泛型版Outcome<T>:
public class Outcome<T> { public bool IsSuccess { get; } public T? Result { get; } public string? ErrorMessage { get; } private Outcome(bool isSuccess, T? result, string? errorMessage) { IsSuccess = isSuccess; Result = result; ErrorMessage = errorMessage; } public static Outcome<T> Success(T result) => new(true, result, null); public static Outcome<T> Fail(string errorMessage) => new(false, default, errorMessage); public static implicit operator bool(Outcome<T> o) => o.IsSuccess; public static bool operator false(Outcome<T> o) => !o.IsSuccess; public static bool operator true(Outcome<T> o) => o.IsSuccess; }
修改你的方法:
private Outcome<Entity> GetSomeEntity() { var entity = GetSomeEntityInternalFunction(); if (entity == null) { return Outcome<Entity>.Fail("Entity is null"); } return Outcome<Entity>.Success(entity); }
调用时无需担心空警告:
var outcome = GetSomeEntity(); if (!outcome) { return outcome; // 如果需要返回非泛版Outcome,可额外转换或调整类型设计 } var entityId = outcome.Result.Id; // 编译器自动推断Result非空
方案2:调整方法签名,返回bool+out参数返回Outcome
保留out参数传递实体,让方法返回bool以触发[NotNullWhen(true)]的推断逻辑,同时通过另一个out参数返回Outcome:
private bool GetSomeEntity([NotNullWhen(true)] out Entity? entity, out Outcome outcome) { entity = GetSomeEntityInternalFunction(); if (entity == null) { outcome = Outcome.Fail("Entity is null"); return false; } outcome = Outcome.Success(); return true; }
调用示例:
if (!GetSomeEntity(out var entity, out var outcome)) { return outcome; } var entityId = entity.Id; // 无空引用警告
方案3:使用编译器指令抑制警告(不推荐)
如果不想修改现有代码结构,可在警告行添加临时抑制指令,但这只是规避问题而非解决根源:
#pragma warning disable CS8602 // 取消可能的空引用警告 var entityId = entity.Id; #pragma warning restore CS8602 // 恢复警告检查
内容的提问来源于stack exchange,提问作者Chebz
相关产品推荐
相关产品推荐

