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

如何在不抛异常时退出调用方法?C#守卫子句优化

在C#中实现无判断的Result式流程控制

我在C#开发中采用Result对象替代异常,通过Web管道过滤器将Result映射为HTTP响应码。现有带守卫子句的代码包含多次仓储调用,虽已做初步重构,但仍需通过判断才能退出方法。我希望Guard(id)或LoadDto3(id)在出错时直接退出Method1,让公共方法只保留核心业务调用,方便业务人员理解流程,该怎么实现?

原代码示例

public Result Method1(string id)
{
    if (string.IsNullOrWhiteSpace(id))
        return ArgumentError(nameof(id));

    var dto1 = _repository1.Get(id);
    if (dto1 == null)
        return NotFoundError();

    var dto2 = _repository2.Get(dto1.Dto2Id);
    if (dto2 == null)
        return NotFoundError();

    var dto3 = _repository3.Get(dto2.Dto3Id);
    if (dto3 == null)
        return NotFoundError();

    Handle(dto3);
}

重构后代码

public Result Method1(string id)
{
    var guardResult = Guard(id);
    if (guardResult.IsFailed)
        return guardResult;

    var dto3 = LoadDto3(id);
    if (dto3 == null)
        return NotFoundError();

    Handle(dto3);
}

期望代码形式

public Result Method1(string id)
{
    Guard(id);
    var dto3 = LoadDto3(id);
    Handle(dto3);
}

实现方案

方案1:链式调用封装(最推荐)

通过定义通用Result<T>类型和扩展方法,把"失败即返回"的逻辑封装起来,让业务方法只保留核心流程调用。

1. 定义基础Result类型

// 错误信息载体
public record Error(string Code, string Message);

// 基础Result类
public class Result
{
    public bool IsSuccess { get; }
    public bool IsFailed => !IsSuccess;
    public Error Error { get; }

    protected Result(bool isSuccess)
    {
        IsSuccess = isSuccess;
        Error = default;
    }

    protected Result(Error error)
    {
        IsSuccess = false;
        Error = error;
    }

    public static Result Success() => new Result(true);
    public static Result Failure(Error error) => new Result(error);
}

// 带返回值的Result类
public class Result<T> : Result
{
    public T Value { get; }

    private Result(T value) : base(true) => Value = value;
    private Result(Error error) : base(error) => Value = default;

    public static new Result<T> Success(T value) => new Result<T>(value);
    public static new Result<T> Failure(Error error) => new Result<T>(error);
}

2. 编写Result扩展方法

public static class ResultExtensions
{
    // 无返回值Result:失败则直接返回,成功则执行后续操作
    public static Result Then(this Result result, Func<Result> action)
    {
        if (result.IsFailed) return result;
        return action();
    }

    // 带返回值Result:失败则直接返回,成功则将值传入后续操作
    public static Result Then<T>(this Result<T> result, Func<T, Result> action)
    {
        if (result.IsFailed) return result;
        return action(result.Value);
    }
}

3. 修改业务方法实现

调整Guard和LoadDto3的返回类型,然后用链式调用重构Method1:

public Result Method1(string id)
{
    return Guard(id)
        .Then(() => LoadDto3(id))
        .Then(dto3 => Handle(dto3));
}

// 守卫方法:返回Result,失败时携带错误信息
private Result Guard(string id)
{
    if (string.IsNullOrWhiteSpace(id))
        return Result.Failure(new Error("InvalidArgument", $"参数 {nameof(id)} 不能为空"));
    return Result.Success();
}

// 加载Dto3的方法:返回Result<Dto3>,失败时返回NotFound错误
private Result<Dto3> LoadDto3(string id)
{
    var dto1 = _repository1.Get(id);
    if (dto1 == null)
        return Result<Dto3>.Failure(new Error("NotFound", "未找到Dto1"));

    var dto2 = _repository2.Get(dto1.Dto2Id);
    if (dto2 == null)
        return Result<Dto3>.Failure(new Error("NotFound", "未找到Dto2"));

    var dto3 = _repository3.Get(dto2.Dto3Id);
    if (dto3 == null)
        return Result<Dto3>.Failure(new Error("NotFound", "未找到Dto3"));

    return Result<Dto3>.Success(dto3);
}

// 业务处理方法:返回Result
private Result Handle(Dto3 dto3)
{
    // 核心业务逻辑
    return Result.Success();
}

这种方式完全消除了判断语句,Method1只保留核心流程的调用链,业务人员能快速理解整个流程的执行顺序。

方案2:局部辅助方法简化判断

如果不想用链式调用,可以封装一个局部辅助方法来减少重复判断:

public Result Method1(string id)
{
    // 局部方法:检查Result是否失败,失败则直接返回
    Result CheckFail(Result result) => result.IsFailed ? result : null;

    var guardFail = CheckFail(Guard(id));
    if (guardFail != null) return guardFail;

    var dto3Result = LoadDto3(id);
    var loadFail = CheckFail(dto3Result);
    if (loadFail != null) return loadFail;

    return Handle(dto3Result.Value);
}

这种方式虽然仍有少量判断,但比原代码简洁很多,且逻辑复用性更高。


内容的提问来源于stack exchange,提问作者fibach

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 03:05:33