如何用装饰器模式在方法执行前后注入行为记录输入输出,无需反射与付费AOP库
无反射装饰器模式实现方法执行前后逻辑注入
下面提供两种完全不依赖反射的装饰器实现方案,均为强类型编译时校验,性能和原生代码几乎无差异,可灵活注入任意自定义前后执行逻辑。
方案1:通用函数包装器(适合零散方法装饰)
你可以写一个通用的泛型扩展方法,针对任意Func<TIn, TOut>委托注入前后执行钩子,无需修改原有业务逻辑:
public static class FunctionDecoratorExtensions { public static Func<TIn, TOut> AddHooks<TIn, TOut>( this Func<TIn, TOut> targetFunction, Action<TIn> beforeExecuting = null, Action<TIn, TOut> afterExecuted = null, Action<Exception> onError = null) { return input => { try { beforeExecuting?.Invoke(input); var result = targetFunction(input); afterExecuted?.Invoke(input, result); return result; } catch (Exception ex) { onError?.Invoke(ex); throw; } }; } }
使用示例
首先把你的核心业务逻辑和日志逻辑解耦:
// 纯业务逻辑,无侵入 private SomeOutputModel CoreBusinessMethod(SomeInputModel model) { return DoSomething(); }
在类初始化时完成方法包装,只需要执行一次:
private readonly Func<SomeInputModel, SomeOutputModel> _decoratedMethod; public YourServiceClass(ILogger<YourServiceClass> logger) { // 把核心方法转为Func委托 Func<SomeInputModel, SomeOutputModel> coreFunc = CoreBusinessMethod; // 注入日志钩子 _decoratedMethod = coreFunc.AddHooks( beforeExecuting: input => logger.LogDebug(JsonSerializer.Serialize(input)), afterExecuted: (_, output) => logger.LogDebug(JsonSerializer.Serialize(output)) ); } // 对外暴露的调用入口 public SomeOutputModel Method(SomeInputModel model) { return _decoratedMethod(model); }
你可以根据需求注入任意自定义逻辑,比如耗时统计、参数校验、重试机制等,无需修改核心业务代码。
方案2:接口装饰器(适配依赖注入场景)
如果你的方法是定义在接口中,使用接口装饰器的方式更适合依赖注入架构,完全无黑盒逻辑,可读性更高:
首先定义业务接口和原始实现:
public interface IBusinessService { SomeOutputModel Method(SomeInputModel model); } // 原始业务实现,无日志逻辑 public class BusinessService : IBusinessService { public SomeOutputModel Method(SomeInputModel model) { return DoSomething(); } }
编写装饰器类实现同一个接口,注入原始实现和自定义逻辑依赖:
public class LoggedBusinessService : IBusinessService { private readonly IBusinessService _innerService; private readonly ILogger<LoggedBusinessService> _logger; public LoggedBusinessService(IBusinessService innerService, ILogger<LoggedBusinessService> logger) { _innerService = innerService; _logger = logger; } public SomeOutputModel Method(SomeInputModel model) { // 执行前自定义逻辑 _logger.LogDebug(JsonSerializer.Serialize(model)); // 调用原始业务逻辑 var result = _innerService.Method(model); // 执行后自定义逻辑 _logger.LogDebug(JsonSerializer.Serialize(result)); return result; } }
DI注册示例(以.NET内置DI为例)
// 注册原始业务实现 services.AddScoped<BusinessService>(); // 注册装饰器,覆盖接口默认实现 services.AddScoped<IBusinessService>(sp => new LoggedBusinessService( sp.GetRequiredService<BusinessService>(), sp.GetRequiredService<ILogger<LoggedBusinessService>>() ));
后续你需要加其他逻辑时,只需要新增对应的装饰器类即可,无需修改原有代码。
内容的提问来源于stack exchange,提问作者Nader Vaghari
相关产品推荐
相关产品推荐

