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

Unity容器中IEnumerable<T>与Log4NetExtension结合的日志名称异常问题

解决Unity.log4net命名注册IEnumerable注入时日志名称异常的问题

我之前遇到过一模一样的问题,踩过这个坑!核心原因是Unity.log4net扩展默认是基于当前解析上下文的目标类型来创建ILog实例的:当你通过IEnumerable<IActivity>注入一批命名注册的实例时,Unity是在解析ActivityExecutor的构造函数参数时去遍历这些注册项,这时候上下文的目标类型是ActivityExecutor,所以所有IActivity实例都会拿到对应ActivityExecutor的日志实例,而不是它们自身类的。

下面给你几个可行的解决方案,从简单到进阶:

方案1:手动为每个命名注册的Activity指定对应ILog

这是最直接的方式,在注册每个IActivity实现时,显式注入对应自身类的ILog实例:

container.RegisterType<IActivity, ActivityA>(nameof(ActivityA),
    new InjectionConstructor(LogManager.GetLogger(typeof(ActivityA))));
container.RegisterType<IActivity, ActivityB>(nameof(ActivityB),
    new InjectionConstructor(LogManager.GetLogger(typeof(ActivityB))));

这样每个ActivityA/ActivityB实例在创建时,都会被注入对应自身类的ILog,日志输出时就会显示正确的类名了。

方案2:用InjectionFactory自动绑定具体类型的ILog

如果你有很多IActivity实现,手动写每个构造函数注入太繁琐,可以用工厂方法统一处理:

container.RegisterType<IActivity, ActivityA>(nameof(ActivityA),
    new InjectionFactory(c => new ActivityA(LogManager.GetLogger(typeof(ActivityA)))));
container.RegisterType<IActivity, ActivityB>(nameof(ActivityB),
    new InjectionFactory(c => new ActivityB(LogManager.GetLogger(typeof(ActivityB)))));

本质和方案1一样,只是用工厂方式简化了实例创建逻辑,确保每个具体类型都拿到自己的日志实例。

方案3:扩展Unity.log4net实现自动匹配命名注册的ILog

如果你的项目中有大量命名注册的类型需要注入正确的ILog,可以自定义扩展来自动化这个过程:

首先创建一个自定义的Log4Net扩展,监听注册事件,自动为命名注册的类型创建对应名称的ILog实例:

public class PerConcreteTypeLogExtension : Log4NetExtension
{
    protected override void Initialize()
    {
        base.Initialize();
        // 监听注册事件,为命名注册的具体类型创建对应ILog
        Context.Registering += (sender, e) =>
        {
            if (string.IsNullOrEmpty(e.Name) || e.TypeTo == null) return;
            
            // 以注册名称为键,注册对应具体类型的ILog
            Container.RegisterInstance<ILog>(e.Name, 
                LogManager.GetLogger(e.TypeTo), 
                new ContainerControlledLifetimeManager());
        };
    }
}

然后替换原来的Log4NetExtension:

// 替换掉原来的container.AddNewExtension<Log4NetExtension>();
container.AddNewExtension<PerConcreteTypeLogExtension>();

最后注册IActivity时,通过名称解析对应的ILog:

container.RegisterType<IActivity, ActivityA>(nameof(ActivityA),
    new InjectionConstructor(new ResolvedParameter<ILog>(nameof(ActivityA))));
container.RegisterType<IActivity, ActivityB>(nameof(ActivityB),
    new InjectionConstructor(new ResolvedParameter<ILog>(nameof(ActivityB))));

这样后续新增命名注册的IActivity时,只需要按这个模式注册,扩展会自动帮你创建对应的ILog实例。

验证你的Activity构造函数

确保你的ActivityA/ActivityB是通过构造函数接收ILog的:

public class ActivityA : IActivity
{
    private readonly ILog _logger;

    public ActivityA(ILog logger)
    {
        _logger = logger;
    }

    public void Execute()
    {
        _logger.Info("Executing ActivityA"); // 现在日志名称会是ActivityA
    }
}

以上三种方案都能解决你的问题,优先推荐方案1或2,简单直接不需要修改扩展;如果有大量类型需要处理,方案3会更高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:29:44