You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 02:30:59