Использование структуры map с оберткой log4net

У меня есть следующий интерфейс:

public interface ILogger
{
    void Debug(string message, params object[] values);
    void Info(string message, params object[] values);
    void Warn(string message, params object[] values);
    void Error(string message, params object[] values);
    void Fatal(string message, params object[] values);
}

и следующую реализацию:

public class Log4netLogger : ILogger
{
    private ILog _log;

    public Log4netLogger(Type type)
    {
        _log = LogManager.GetLogger(type);
    }

    public void Debug(string message, params object[] values)
    {
        _log.DebugFormat(message, values);
    }

    // other logging methods here...

}

Моя идея состояла в том, чтобы использовать structmap для создания экземпляра класса Log4netLogger с использованием типа класса, который выполнял ведение журнала. Тем не менее, я не могу на всю жизнь понять, как передать тип вызывающего класса структуре, чтобы он мог быть передан конструктору реализации журнала. Любые советы о том, как это сделать (или лучший способ), будут наиболее оценены.

Ответ 1

Если параметр типа является контекстным, я не думаю, что это будет работать, как показано. Если вам нужно передать что-то конкретное в конструкторе, вам, скорее всего, придется создать интерфейс и реализацию factory, который возвращает экземпляр ILogger:

public interface ILoggerFactory
{
    ILogger Create(Type type);   
}

public class LoggerFactory : ILoggerFactory
{
    public ILogger Create(Type type)
    {
        return new Log4netLogger(type);
    }
}

Возможно, будет возможно загрузочная структура StructureMap, чтобы предоставить экземпляр, который вы хотите, на основе типа, но это предполагает ограниченное количество типов, которые вы знаете заранее.

Ответ 2

Мы используем аналогичную оболочку ILogger вокруг log4net и обычно используем инъекцию конструктора. Мы используем перехватчик как метод factory, ответственный за создание Регистратора. Вот наш типичный реестр для настройки ведения журнала.

public class CommonsRegistry : Registry
{
    public CommonsRegistry()
    {
        For<ILogger>()
            .AlwaysUnique()
            .TheDefault.Is.ConstructedBy(s =>
            {
                if (s.ParentType == null)
                    return new Log4NetLogger(s.BuildStack.Current.ConcreteType);

                return new Log4NetLogger(s.ParentType);
            });

        var applicationPath = Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location);
        var configFile = new FileInfo(Path.Combine(applicationPath, "log4net.config"));
        XmlConfigurator.ConfigureAndWatch(configFile);
    }
}

Нулевая проверка родительского типа необходима, если существуют зависимости от конкретных типов.

Остальное - необязательный файл настройки log4net.

Одна вещь, которая мне нравится в этой настройке, - это возможность использовать пустые регистраторы для модульного тестирования.

Ответ 3

Мне действительно нужно избавиться от привычки отвечать на свой вопрос, но для тех, кто сталкивается с ним, вот ответ.

return ObjectFactory.With(type).GetInstance<T>();

На самом деле у меня есть оболочка для структуры (чтобы не подвергать зависимость структуры в моем приложении), которая выглядит следующим образом:

public static class ServiceManager
{
    public static T Get<T>()
    {
        return ObjectFactory.GetInstance<T>();
    }

    public static T Get<T>(Type type)
    {
        return ObjectFactory.With(type).GetInstance<T>();
    }
}

В любое время в коде мне нужен регистратор, я вызываю следующее:

ServiceManager.Get<ILogger>(GetType()).Info("Logging page view...");