У меня есть следующий интерфейс:
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...
}
Моя идея состояла в том, чтобы использовать structuremap для инстанцирования класса Log4netLogger с использованием Типа класса, который сделал вход. Однако я не могу ни за что в жизни выяснить, как передать тип класса вызова к structuremap так, чтобы он мог быть передан конструктору регистрирующейся реализации. Любой совет относительно того, как сделать это (или лучший путь) больше всего ценился бы.
Если типовой параметр является контекстно-зависимым, то я не думаю, что это сработает, как показано на рисунке. Если вам нужно передать что-то специфическое для контекста в конструкторе, то вам, скорее всего, придется создать заводской интерфейс и реализацию, возвращающую экземпляр ILogger:
public interface ILoggerFactory
{
ILogger Create(Type type);
}
public class LoggerFactory : ILoggerFactory
{
public ILogger Create(Type type)
{
return new Log4netLogger(type);
}
}
Возможно, можно загрузить StructureMap для поставки нужного вам экземпляра на основе типа, но это предполагает ограниченное количество заранее известных типов.
.Мне действительно нужно избавиться от привычки отвечать на свой собственный вопрос, но для тех, кто его пересекает, вот ответ.
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...");
Мы используем подобную ILogger-обертку вокруг log4net и обычно используем впрыск конструктора. Мы используем перехватчик как заводской метод, отвечающий за создание логгера. Вот наш типичный реестр для настройки логов.
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.
Одна вещь, которая мне нравится в этой настройке, это возможность использовать нулевой логгер для юнит-тестирования.