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

如何用装饰器模式在方法执行前后注入行为记录输入输出,无需反射与付费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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 11:36:03