Использование LogManager.GetLogger с Unity - PullRequest
5 голосов
/ 20 декабря 2011

Учитывая этот класс:

class Foo
{
    readonly ILog log;

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

    ...
}

Я бы хотел настроить Unity для внедрения ILog. Это просто:

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

Но я бы хотел сделать вызов Unity 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, но можно ли это сделать? :)

Ответы [ 3 ]

6 голосов
/ 21 декабря 2011

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);

Вы можете найти исходный код для TrackingExtension здесь . Он находится в папке проекта TecX.Unity .

3 голосов
/ 22 декабря 2011

Если вы хотите, чтобы контейнер 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();
        }
    }
}
2 голосов
/ 11 апреля 2013

Это похоже на очень чистый подход: https://github.com/roblevine/UnityLoggingExtensions

...