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

如何在不修改接口所在DLL的前提下,统一为Handle()方法添加日志?

可行方案(无需修改原DLL)

完全可以在不修改原DLL和现有149个Handle方法的前提下实现统一日志注入,以下是几种实用方案:

1. 装饰器模式(无第三方依赖)

实现一个泛型装饰器类,包装所有IMessageHandler<TMessage>的实现,统一在Handle方法前添加日志逻辑:

步骤1:定义泛型装饰器

public class LoggingMessageHandler<TMessage> : IMessageHandler<TMessage>
{
    private readonly IMessageHandler<TMessage> _targetHandler;
    private readonly ILogger _log;

    public LoggingMessageHandler(IMessageHandler<TMessage> targetHandler, ILogger log)
    {
        _targetHandler = targetHandler;
        _log = log;
    }

    public void Handle(TMessage message)
    {
        // 统一添加日志
        _log.Debug($"Handling [{message.GetType().Name}]");
        // 调用原Handle方法
        _targetHandler.Handle(message);
    }
}

步骤2:替换原有实例

将原来直接创建的GeneralManager、SpecificManager实例,替换为装饰后的实例:

// 原代码:var manager = new GeneralManager();
var rawManager = new GeneralManager();
var loggingManager = new LoggingMessageHandler<GetStockMessage>(rawManager, log);

// 如果是依赖注入环境(比如ASP.NET Core),可以批量注册:
services.AddScoped(typeof(IMessageHandler<>), typeof(LoggingMessageHandler<>));
// 再注册实际的实现类
services.AddScoped<IMessageHandler<GetStockMessage>, GeneralManager>();
services.AddScoped<IMessageHandler<GetListMessage>, SpecificManager>();
// 注:部分DI容器(如Autofac)有专门的AddDecorator方法,更方便批量装饰

2. AOP切面框架(最省心)

使用AOP框架(如PostSharp、Castle DynamicProxy)通过切面拦截所有Handle方法,自动注入日志:

示例:PostSharp实现

  1. 定义日志切面特性:
[Serializable]
public class LogMessageHandlingAttribute : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        // 仅拦截IMessageHandler的Handle方法
        if (args.Method.Name == nameof(IMessageHandler<object>.Handle) && args.Arguments.Length > 0)
        {
            var message = args.Arguments[0];
            var log = LogManager.GetLogger(args.Method.DeclaringType);
            log.Debug($"Handling [{message.GetType().Name}]");
        }
    }
}
  1. 全局应用切面:
    可以直接给所有实现IMessageHandler<T>的类加[LogMessageHandling]特性,或者通过PostSharp的全局配置,自动对所有匹配的Handle方法应用该切面,无需逐个修改类。

示例:Castle DynamicProxy实现

  1. 定义拦截器:
public class LoggingInterceptor : IInterceptor
{
    private readonly ILogger _log;

    public LoggingInterceptor(ILogger log)
    {
        _log = log;
    }

    public void Intercept(IInvocation invocation)
    {
        // 拦截Handle方法
        if (invocation.Method.Name == nameof(IMessageHandler<object>.Handle) && invocation.Arguments.Any())
        {
            var message = invocation.Arguments[0];
            _log.Debug($"Handling [{message.GetType().Name}]");
        }
        // 执行原方法
        invocation.Proceed();
    }
}
  1. 生成代理实例:
var proxyGenerator = new ProxyGenerator();
// 给GeneralManager生成代理,自动拦截所有Handle方法
var proxiedManager = proxyGenerator.CreateClassProxy<GeneralManager>(new LoggingInterceptor(log));

3. 反射+动态代码生成(适合特殊场景)

如果无法修改实例创建逻辑,也可以通过反射获取所有实现IMessageHandler<T>的类,使用Roslyn或Emit动态生成带日志的包装类,替换原有类型的实例。这种方式复杂度较高,适合不能用前两种方案的极端场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:34:52