使用LogManager.GetLogger使用Unity

问题描述:

鉴于这种类:使用LogManager.GetLogger使用Unity

class Foo 
{ 
    readonly ILog log; 

    public Foo(ILog log) 
    { 
     this.log = log; 
    } 

    ... 
} 

我想配置统一注入的ILog。这很简单:

container.RegisterInstance<ILog>(LogManager.GetLogger(typeof(XYZ))); 

但我想使统一呼叫LogManager.GetLogger与父类型的类型解决。

这是接近:

container.RegisterType<ILog>(new InjectionFactory((c, t, s) => LogManager.GetLogger(t))); 

t在这种情况下得到解决的类型(ILog),而不是类型的对象正在解决的(Foo)。

我知道我能做到这一点:

container.RegisterType<Foo>(new InjectionFactory(c => new Foo(LogManager.GetLogger(typeof(Foo))); 

但我不希望有每次我注册一个对象时补充说,疯狂的宣言。

我知道这可以在Autofac中完成,而且我知道真正的答案并不是首先使用Unity,但是可以这样做吗? :)

Unity可能不会给你所有其他容器提供的好东西,但我还没有找到一个你不容易添加的功能。

var container = new UnityContainer(); 
container.AddNewExtension<TrackingExtension>(); 
container.RegisterType<ILog>(
    new InjectionFactory((ctr, type, name) => 
    { 
     var tracker = ctr.Resolve<ITracker>(); 
     var parentType = tracker.CurrentBuildNode.Parent.BuildKey.Type; 
     return LogManager.GetLogger(parentType); 
    })); 
var sut = container.Resolve<UsesLog>(); 
Assert.AreEqual(typeof(UsesLog), sut.Log.Type); 

你可以找到的TrackingExtensionhere的源代码。它位于TecX.Unity项目文件夹中。

+0

谢谢,我最终选择了基于相同模型的东西。我发现的一件事是我必须实施IRecovery来处理PostBuildUp未被调用的情况。 – 2011-12-22 18:15:05

+0

_TrackingStrategy_的_PostBuildUp_没有被调用?据我所知,只有当策略声明在_PreBuildUp_中的构建完成(它没有)或者管道中过早插入链的异常时,这种情况才有可能。 – 2011-12-23 10:56:24

+0

没错。我不确定是否有例外,但我们确实有一些可能无法加载的[OptionalDependencies],所以没有什么可以* PostBuildUp *。 – 2011-12-23 12:27:55

如果您希望DI容器根据类的类型信息返回记录器,然后将类型信息放入公共接口,以便DI容器可以看到它。它不需要任何容器特定的重写功能,如果您使用Unity或AutoFac,则无关紧要。

有人说知道log4net的对象模型以及也许能够给你一个更有效的实现,但尝试这样的事:

using System; 
using Microsoft.Practices.Unity; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace UnityLoging 
{ 
    public interface ILog<T> : log4net.ILog 
    { } 

    public class MyLogger<T> : log4net.Core.LogImpl, ILog<T> 
    { 
     public MyLogger() : base(log4net.LogManager.GetLogger(typeof(T).Name).Logger) 
     { } 
    } 

    public class ClassToLog 
    { 
     private readonly log4net.ILog log; 

     public ClassToLog(ILog<ClassToLog> log) 
     { 
      this.log = log; 
     } 

     public void LogMe() 
     { 
      log.Debug("Got here"); 
     } 
    } 

    [TestClass] 
    public class TestClass 
    { 
     [TestMethod] 
     public void GenericLogRegistrationTest() 
     { 
      log4net.Config.XmlConfigurator.Configure(); 
      IUnityContainer container = new UnityContainer(); 
      container.RegisterType(typeof(ILog<>), typeof(MyLogger<>)); 

      ClassToLog c = container.Resolve<ClassToLog>(); 
      c.LogMe(); 

      log4net.LogManager.Shutdown(); 
     } 
    } 
} 
+0

有趣的方法。它是容器不可知的,但有点冗长,开发人员需要知道_ILog中的_T_必须与记录器作为依赖项的类的类型相匹配。 – 2011-12-23 10:49:20

这似乎是一个很干净的做法:https://github.com/roblevine/UnityLoggingExtensions