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

如何封装BusinessObject实现方法插桩 无需编写大量Execute重载

解决方案

针对你遇到的两个问题,提供两种可落地的实现方案:

方案一:基于现有Wrapper逻辑简化,无需引入第三方依赖

核心思路是用Lambda表达式捕获方法参数,不需要再为不同参数数量的方法写独立的Execute重载,也不需要调用时手动指定泛型参数。

修改后的Wrapper核心代码

// 仅保留两个核心重载,分别处理有返回值和无返回值的场景
public class BoWrapper
{
    private readonly BaseBo _boInstance;
    private readonly ILogger _logger;

    public BoWrapper(BaseBo boInstance)
    {
        _boInstance = boInstance;
        // 日志初始化逻辑保持不变
    }

    // 处理无返回值方法
    public OperationResultDto<object> Execute(Delegate targetMethod, Token token, Action invokeAction)
    {
        return InternalExecute(targetMethod, token, invokeAction);
    }

    // 处理有返回值方法
    public OperationResultDto<TResult> Execute<TResult>(Delegate targetMethod, Token token, Func<TResult> invokeFunc)
    {
        try
        {
            if (targetMethod == null) throw new ArgumentNullException(nameof(targetMethod));
            if (invokeFunc == null) throw new ArgumentNullException(nameof(invokeFunc));

            _logger.Debug(DumpParameters(targetMethod.Method, invokeFunc.Target));
            var permissionAttr = targetMethod.Method.GetCustomAttributes(false).OfType<PermissionRequired>().FirstOrDefault();
            // 原有权限校验逻辑保持不变

            var result = invokeFunc();
            _logger.Debug($"方法 {targetMethod.Method.Name} 调用结束");
            return new OperationResultDto<TResult> { Success = true, ReturnData = result };
        }
        catch (Exception ex)
        {
            _logger.Error(ex, string.Empty);
            return new OperationResultDto<TResult>
            {
                Success = false,
                ErrorText = ex.Message,
                Error = ex,
                ReturnData = default
            };
        }
    }

    protected virtual OperationResultDto<object> InternalExecute(Delegate targetMethod, Token token, Action invokeAction)
    {
        try
        {
            if (targetMethod == null) throw new ArgumentNullException(nameof(targetMethod));
            if (invokeAction == null) throw new ArgumentNullException(nameof(invokeAction));

            _logger.Debug(DumpParameters(targetMethod.Method, invokeAction.Target));
            var permissionAttr = targetMethod.Method.GetCustomAttributes(false).OfType<PermissionRequired>().FirstOrDefault();
            // 原有权限校验逻辑保持不变

            invokeAction();
            _logger.Debug($"方法 {targetMethod.Method.Name} 调用结束");
            return new OperationResultDto<object> { Success = true, ReturnData = null };
        }
        catch (Exception ex)
        {
            _logger.Error(ex, string.Empty);
            return new OperationResultDto<object>
            {
                Success = false,
                ErrorText = ex.Message,
                Error = ex,
                ReturnData = null
            };
        }
    }

    // DumpParameters等原有工具方法保持不变
}

调用方式

不需要手动指定泛型,不管方法有多少参数都可以直接适配:

TestBo testBo = new TestBo("Identity");
Token token = new Token(1);
BoWrapper wrapper = new BoWrapper(testBo);

// 无参数无返回值方法调用
wrapper.Execute(testBo.ExampleMethod, token, () => testBo.ExampleMethod());
// 带参数无返回值方法调用
wrapper.Execute(testBo.WriteMessage, token, () => testBo.WriteMessage("Message"));
// 带返回值、多参数方法自动适配,无需手动指定泛型
var dataResult = wrapper.Execute(testBo.GetDetail, token, () => testBo.GetDetail("id_001", true));

方案二:动态代理实现无侵入插桩,彻底消除额外调用成本

如果可以引入轻量级第三方库,Castle DynamicProxy是该场景的最优解,不需要写任何Execute重载,也不需要改变原有BO的调用习惯。

实现步骤

  1. 实现拦截器,把日志、权限校验的公共逻辑放到拦截器中:
public class BoAopInterceptor : IInterceptor
{
    private readonly ILogger _logger;
    private readonly Token _token;

    public BoAopInterceptor(ILogger logger, Token token)
    {
        _logger = logger;
        _token = token;
    }

    public void Intercept(IInvocation invocation)
    {
        try
        {
            _logger.Debug(DumpParameters(invocation.Method, invocation.Arguments));
            var permissionAttr = invocation.Method.GetCustomAttributes(false).OfType<PermissionRequired>().FirstOrDefault();
            // 原有权限校验逻辑保持不变

            // 执行原BO的方法
            invocation.Proceed();

            _logger.Debug($"方法 {invocation.Method.Name} 调用结束");
            // 可根据需求统一包装返回值为OperationResultDto格式
        }
        catch (Exception ex)
        {
            _logger.Error(ex, string.Empty);
            invocation.ReturnValue = new OperationResultDto<object>
            {
                Success = false,
                ErrorText = ex.Message,
                Error = ex,
                ReturnData = null
            };
        }
    }
}
  1. 生成BO代理实例,直接按照原有方式调用即可:
var proxyGenerator = new ProxyGenerator();
Token token = new Token(1);
// 直接生成TestBo的代理实例,构造参数和原类完全一致
TestBo proxyBo = proxyGenerator.CreateClassProxy<TestBo>(
    new BoAopInterceptor(_logger, token), 
    new object[] { "Identity" }
);

// 完全和原生BO的调用方式一致,不需要调用Execute方法
proxyBo.ExampleMethod();
proxyBo.WriteMessage("Message");
var result = proxyBo.GetDetail("id_001", true);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 23:30:03