具有附加依赖性的简单注入器装饰
Simple Injector decoration with additional dependency
我有一个装饰器 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);
}
}
如何使用简单注入器用 SomethingLoggerDecorator
装饰 ISomething
的实例,并使用静态工厂方法 LogManager.GetLogger(decoratee.GetType())
将 ILogger
的实例注入到每个装饰器中] decoratee 是要被装饰的实际实例?此外,注入的 ILogger
和 SomethingLoggerDecorator
的生命周期应始终与装饰者的生命周期相匹配。
在 Simple Injector 中有多种方法可以做到这一点。
首先,你可以让你的装饰器的构造函数依赖于DecoratorContext class。 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
class 的缺点是你的装饰器需要依赖简单注入器,这基本上意味着你必须将装饰器移动到你的 Composition Root to prevent your application from taking a dependency on the DI library. You can find more information about the use of this DecoratorContext
class 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
}
}
我有一个装饰器 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);
}
}
如何使用简单注入器用 SomethingLoggerDecorator
装饰 ISomething
的实例,并使用静态工厂方法 LogManager.GetLogger(decoratee.GetType())
将 ILogger
的实例注入到每个装饰器中] decoratee 是要被装饰的实际实例?此外,注入的 ILogger
和 SomethingLoggerDecorator
的生命周期应始终与装饰者的生命周期相匹配。
在 Simple Injector 中有多种方法可以做到这一点。
首先,你可以让你的装饰器的构造函数依赖于DecoratorContext class。 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
class 的缺点是你的装饰器需要依赖简单注入器,这基本上意味着你必须将装饰器移动到你的 Composition Root to prevent your application from taking a dependency on the DI library. You can find more information about the use of this DecoratorContext
class 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
}
}