我有一个装饰器SomethingLoggerDecorator
,它应该用日志来装饰ISomething
个实例:
public class SomethingLoggerDecorator : ISomething
{
private readonly ISomething decoratee;
private readonly ILogger logger;
public SomethingLoggerDecorator(ISomething decoratee, ILogger logger)
{
this.decoratee = decoratee;
this.logger = logger;
}
public void DoSomething()
{
this.logger.Info("Doing Something");
this.decoratee.DoSomething();
}
public void DoSomethingElse(string withThis)
{
this.logger.Info("Doing Something Else with " + withThis);
this.decoratee.DoSomethingElse(withThis);
}
}
如何使用Simple Injector使用ISomething
装饰SomethingLoggerDecorator
的实例,并使用静态工厂方法ILogger
将LogManager.GetLogger(decoratee.GetType())
的实例注入每个装饰器中decoratee是要装饰的实际实例?注入的ILogger
以及SomethingLoggerDecorator
的生命周期也应始终与decoratee的生命周期相匹配。
答案 0 :(得分:2)
在Simple Injector中有多种方法可以做到这一点。
首先,您可以让装饰器的构造函数依赖于DecoratorContext类。 DecoratorContext
包含有关装饰器的上下文信息。它包含诸如包装装饰器的类型和装饰的实际实现的类型(真实实例)之类的信息。所以你的装饰者可能看起来如下:
public class SomethingLoggerDecorator : ISomething
{
private readonly ISomething decoratee;
private readonly DecoratorContext context;
public SomethingLoggerDecorator(ISomething decoratee, DecoratorContext context)
{
this.decoratee = decoratee;
this.context = context;
}
public void DoSomething()
{
var logger = LogManager.GetLogger(this.context.ImplementationType);
logger.Info("Doing Something");
this.decoratee.DoSomething();
}
}
使用这个DecoratorContext
类的缺点是你的装饰者需要依赖于Simple Injector,这基本上意味着你必须在Composition Root内移动装饰器以防止你的应用程序依赖于DI库。您可以找到有关使用此DecoratorContext
课程here的更多信息。
另一种选择是让你的装饰器通用,并为可以制作正确装饰器的RegisterDecorator
重载之一提供装饰器类型工厂。例如:
public class SomethingLoggerDecorator<TImplementation> : ISomething
{
private readonly ISomething decoratee;
public SomethingLoggerDecorator(ISomething decoratee)
{
this.decoratee = decoratee;
}
public void DoSomething()
{
var logger = LogManager.GetLogger(typeof(TImplementation));
logger.Info("Doing Something");
this.decoratee.DoSomething();
}
}
或者可选:
public class SomethingLoggerDecorator<TImplementation> : ISomething
{
private readonly ISomething decoratee;
private readonly ILogger<TImplementation> logger;
public SomethingLoggerDecorator(ISomething decoratee, ILogger<TImplementation> logger)
{
this.decoratee = decoratee;
this.logger = logger;
}
public void DoSomething()
{
this.logger.Info("Doing Something");
this.decoratee.DoSomething();
}
}
通过这两种实现,您可以按如下方式注册装饰器:
container.RegisterDecorator(typeof(ISomething),
c => typeof(SomethingLoggerDecorator<>).MakeGenericType(c.ImplementationType),
Lifestyle.Transient,
predicate: c => true);
使用第二个实现,您将把问题稍微移到泛型ILogger<T>
抽象,但实现可能如下所示:
public class Log4netAdapter<T> : ILogger<T>
{
public void Log(LogEntry entry) {
var logger = LogManager.GetLogger(typeof(T));
// TODO: log
}
}