如何封装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的调用习惯。
实现步骤
- 实现拦截器,把日志、权限校验的公共逻辑放到拦截器中:
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 }; } } }
- 生成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
相关产品推荐
相关产品推荐

