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

实现带Out参数的委托调用:数据库事务装饰器模式遇技术难题

处理带Out参数的委托的事务安全执行方法

我完全懂你碰到的这个坎儿——标准的Action和Func用来封装事务错误处理简直顺手,但带out参数的方法就没法直接套现成的委托了。你自定义的FuncWithOut<T1, T2, TResult>路子是对的,接下来咱们就基于这个委托实现对应的安全执行逻辑,完美适配事务的提交/回滚需求。

第一步:实现适配FuncWithOut的安全执行方法

我们可以直接照搬你之前SafetyExecuteMethod(Action action)的思路,只是调整参数和返回值来适配带out参数的委托:

// 先确认你已经定义了这个自定义委托
public delegate TResult FuncWithOut<T1, T2, TResult>(T1 arg1, out T2 arg2);

// 对应的事务安全执行方法
private TResult SafetyExecuteMethod<T1, T2, TResult>(FuncWithOut<T1, T2, TResult> func, T1 arg1, out T2 arg2)
{
    TResult result = default;
    arg2 = default; // 必须先初始化out参数,否则编译器会报错
    
    // 这里替换成你实际的数据库事务初始化逻辑,比如SqlConnection的BeginTransaction
    using (var transaction = YourDbConnection.BeginTransaction())
    {
        try
        {
            // 执行传入的带out参数的业务方法
            result = func(arg1, out arg2);
            // 执行成功则提交事务
            transaction.Commit();
        }
        catch (Exception ex)
        {
            // 出错立即回滚事务
            transaction.Rollback();
            // 这里可以添加你的错误处理逻辑,比如日志记录、异常包装等
            Console.WriteLine($"事务执行失败:{ex.Message}");
            throw; // 根据业务需求决定是否抛出异常
        }
    }

    return result;
}

第二步:实际调用示例

假设你有一个带out参数的数据库业务方法,比如创建用户并返回生成的用户ID:

// 模拟的业务方法:创建用户,out参数返回生成的用户ID,返回值是受影响行数
private int CreateUser(string username, out Guid userId)
{
    // 这里写实际的数据库插入逻辑
    userId = Guid.NewGuid();
    Console.WriteLine($"创建用户:{username},ID:{userId}");
    return 1;
}

调用安全执行方法的方式和普通方法一致:

Guid newUserId;
int affectedRows = SafetyExecuteMethod(CreateUser, "MaximChervyakov", out newUserId);
Console.WriteLine($"执行结果:受影响行数{affectedRows},用户ID{newUserId}");

扩展:支持多个Out参数

如果你的业务方法需要多个out参数,只需要扩展自定义委托和对应的执行方法即可:

// 支持两个out参数的委托
public delegate TResult FuncWithOut<T1, T2, T3, TResult>(T1 arg1, out T2 arg2, out T3 arg3);

// 对应的安全执行方法
private TResult SafetyExecuteMethod<T1, T2, T3, TResult>(FuncWithOut<T1, T2, T3, TResult> func, T1 arg1, out T2 arg2, out T3 arg3)
{
    TResult result = default;
    arg2 = default;
    arg3 = default;
    
    using (var transaction = YourDbConnection.BeginTransaction())
    {
        try
        {
            result = func(arg1, out arg2, out arg3);
            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            Console.WriteLine($"事务执行失败:{ex.Message}");
            throw;
        }
    }

    return result;
}

这个思路和你之前处理Action的逻辑完全一致,只是针对out参数做了必要的初始化和参数传递适配,完美解决带out参数方法的事务错误处理问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:02:21