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

C# .NET如何实现可携带业务信息的自定义awaitable Task类

实现方案

核心思路

基于原生Task做轻量封装,无需重写复杂的可等待类型逻辑,即可满足你期望的调用方式:await后直接获取业务结果,同时可直接访问ServiceTask实例上的业务状态属性。

第一步:定义泛型ServiceTask类

public class ServiceTask<T>
{
    // 内部承载原生Task执行逻辑
    public Task<T> InnerTask { get; }
    public bool Success { get; internal set; }
    public string ErrorMessage { get; internal set; } = string.Empty;

    // 实现可等待模式要求的GetAwaiter方法,直接转发原生Task的Awaiter
    public TaskAwaiter<T> GetAwaiter() => InnerTask.GetAwaiter();

    internal ServiceTask(Task<T> innerTask)
    {
        InnerTask = innerTask;
    }

    // 成功场景构造方法
    public static ServiceTask<T> FromResult(T result)
    {
        return new ServiceTask<T>(Task.FromResult(result))
        {
            Success = true
        };
    }

    // 业务失败场景构造方法,直接解决你无法设置业务属性的问题
    public static ServiceTask<T> FromError(string errorMsg, T? defaultResult = default)
    {
        return new ServiceTask<T>(Task.FromResult(defaultResult))
        {
            Success = false,
            ErrorMessage = errorMsg
        };
    }

    // 适配包含IO操作的异步逻辑构造
    public static async ServiceTask<T> FromAsync(Func<Task<T>> func, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        try
        {
            var result = await func();
            return FromResult(result);
        }
        catch (OperationCanceledException)
        {
            throw; // 取消操作按原生逻辑抛出
        }
        catch (Exception ex)
        {
            // 程序异常可按需求选择抛出或走业务错误通路
            return FromError(ex.Message);
        }
    }
}

第二步:调整仓储方法实现

完全不需要限制泛型参数为ServiceResponse子类,业务状态和返回结果完全解耦:

public ServiceTask<IEnumerable<Account>?> GetAccountsAsync(Filter filter, CancellationToken token)
{
    // 模拟带过滤条件的数据库查询
    var accounts = DbContext.Accounts.Where(filter?.Expression ?? x => true).ToList();
    if(accounts.Any())
    {
        return ServiceTask<IEnumerable<Account>>.FromResult(accounts);
    }
    else if(filter != null)
    {
        return ServiceTask<IEnumerable<Account>>.FromError("Filter has restricted all Accounts");
    }
    else
    {
        return ServiceTask<IEnumerable<Account>>.FromError("Database doesn't contain any Accounts");
    }
}

第三步:调用方式完全符合你的预期

var t = AccountResposistory.GetAccountsAsync(filter, token);
var results = await t;
if(t.Success)
{
    return Results.Ok(results);
}
else
{
    return Results.Problem(t.ErrorMessage);
}

问题针对性说明

  1. 你提到的无法给ServiceTask设置业务属性的问题:通过静态构造方法FromError/FromResult在实例返回前直接完成属性赋值,无需手动操作实例
  2. 不需要限制泛型T为ServiceResponse子类:业务状态属性直接封装在ServiceTask本身,和返回的业务结果T完全解耦,支持返回任意类型的业务结果,无需额外套Response壳

额外扩展

如果需要无返回值的异步方法,可单独实现非泛型的ServiceTask类,逻辑和泛型版一致即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 10:54:04