Windsor - 装饰所有找到的实现
Windsor - decorate all found implementations
我有一个获取数据的接口,IGetter<IEvent>
,它有几个实现(每个都用于从其他类型的源获取数据)。这个接口是通用的,因为它的实现可以 return 不同类型的事件(SourceEvent
和 StatisticsEvent
,但是两者都基于 IEvent
接口)。
这是一个示例代码(包含隐藏的细节以缩短 post - LINQPad 的完整工作演示是 here)。正在注册装饰器,但未解决。仅解析 Getters
,没有日志记录和缓存功能。
我应该如何注册此代码以使装饰器工作?
// An interface defining an event, "something happened at time When"
public interface IEvent { DateTime When { get; set; }}
// They come from a number of sources (e.g. Windows Event Log, sent e-Mails, disk activity, actions logged in issue tracker etc.)
public class SourceEvent : IEvent { public DateTime When { get; set; } public string What { get; set; }}
// Some implementations:
public class MailEvent : SourceEvent { }
public class FileEvent : SourceEvent { }
// List of all events returned from all implemented sources will be ultimately calculated into activity level at any given time
public class StatisticsEvent : IEvent { public DateTime When { get; set; } public int HowMany{ get; set; }}
// An interface for a class capable of reading IEvents from one source
public interface IGetter<TData> where TData : IEvent { /*...*/ }
// Some implementations
public class MailGetter : IGetter<MailEvent> { /*...*/ }
public class FileGetter : IGetter<FileEvent> { /*...*/ }
// Implementation of this is also based on IGetter (but it gets data from all other IGetters - simplified in this example)
public class StatisticsGetter : IGetter<StatisticsEvent> { /*...*/ }
// Decorators for IGetters - all the magical things I want Getters to be able do
public class Cache<TData> : IGetter<TData> where TData : IEvent { /*...*/ }
public class Logger<TData> : IGetter<TData> where TData : IEvent { /*...*/ }
void Main(string[] args)
{
// Dependency Injection registration
var ioc = new WindsorContainer();
ioc.Register(
Component.For(typeof(IGetter<>)).ImplementedBy(typeof(Cache<>)),
Component.For(typeof(IGetter<>)).ImplementedBy(typeof(Logger<>)), // Decorators registered here are not being injected
Classes.FromThisAssembly()
.BasedOn(typeof(IGetter<>))
.WithServiceBase() // Getters for all sources are registered fine
);
var source1 = ioc.Resolve<IGetter<MailEvent>>();
source1.Query().Dump("Source 1 - \"Querying mails\"");
source1.Query().Dump("Source 1 - \"From cache\""); // Doesn't read from cache, instead it queries again
var source2 = ioc.Resolve<IGetter<FileEvent>>();
source2.Query().Dump("Source 2 - \"Querying files\"");
source2.Query().Dump("Source 2 - \"From cache\"");
var stats = ioc.Resolve<IGetter<StatisticsEvent>>(); // All implementations of IGetter and all implementations of IEvent must be successfully resovled
stats.Query().Dump("Statistics - \"Querying stats\"");
stats.Query().Dump("Statistics - \"From cache\"");
// This works, but we need Windsor to do it for us
// var manual = new Cache<MailEvent>(new Logger<MailEvent>(new MailGetter()));
// manual.Query().Dump("Manual - \"Querying mails\"");
// manual.Query().Dump("Manual - \"From cache\"");
}
您 运行 对 Castle Windsor 决定解决依赖关系的顺序和优先级的方式相当固执己见。
因为你有一个开放的泛型注册,或者更确切地说你有两个,而且还有大量的具体类型注册,所以它会优先考虑具体的实现。
关于如何解决这个问题有几种思路。
所有泛型装饰器的手动显式注册
ioc.Register(
Component.For<IGetter<MailEvent>>().ImplementedBy<Logger<MailEvent>>(),
Component.For<IGetter<FileEvent>>().ImplementedBy<Logger<FileEvent>>(),
Component.For<IGetter<StatisticsEvent>>().ImplementedBy<Logger<StatisticsEvent>>(),
Component.For<IGetter<MailEvent>>().ImplementedBy<Cache<MailEvent>>(),
Component.For<IGetter<FileEvent>>().ImplementedBy<Cache<FileEvent>>(),
Component.For<IGetter<StatisticsEvent>>().ImplementedBy<Cache<StatisticsEvent>>(),
Classes.FromThisAssembly()
.BasedOn(typeof(IGetter<>))
.WithServiceBase() // Getters for all sources are registered fine
);
缺点是很容易忘记注册另一个装饰器,但它可以解决问题。
拦截器(根据他们的 documentation)
您的里程可能会因这些而异,因为它们有效地代理了您的实施并在执行之前或之后采取行动。它们有点像装饰器,但不是纯粹意义上的装饰器。
根据已接受的答案 here.
手动实施 ISubDependencyResolver
我有一个获取数据的接口,IGetter<IEvent>
,它有几个实现(每个都用于从其他类型的源获取数据)。这个接口是通用的,因为它的实现可以 return 不同类型的事件(SourceEvent
和 StatisticsEvent
,但是两者都基于 IEvent
接口)。
这是一个示例代码(包含隐藏的细节以缩短 post - LINQPad 的完整工作演示是 here)。正在注册装饰器,但未解决。仅解析 Getters
,没有日志记录和缓存功能。
我应该如何注册此代码以使装饰器工作?
// An interface defining an event, "something happened at time When"
public interface IEvent { DateTime When { get; set; }}
// They come from a number of sources (e.g. Windows Event Log, sent e-Mails, disk activity, actions logged in issue tracker etc.)
public class SourceEvent : IEvent { public DateTime When { get; set; } public string What { get; set; }}
// Some implementations:
public class MailEvent : SourceEvent { }
public class FileEvent : SourceEvent { }
// List of all events returned from all implemented sources will be ultimately calculated into activity level at any given time
public class StatisticsEvent : IEvent { public DateTime When { get; set; } public int HowMany{ get; set; }}
// An interface for a class capable of reading IEvents from one source
public interface IGetter<TData> where TData : IEvent { /*...*/ }
// Some implementations
public class MailGetter : IGetter<MailEvent> { /*...*/ }
public class FileGetter : IGetter<FileEvent> { /*...*/ }
// Implementation of this is also based on IGetter (but it gets data from all other IGetters - simplified in this example)
public class StatisticsGetter : IGetter<StatisticsEvent> { /*...*/ }
// Decorators for IGetters - all the magical things I want Getters to be able do
public class Cache<TData> : IGetter<TData> where TData : IEvent { /*...*/ }
public class Logger<TData> : IGetter<TData> where TData : IEvent { /*...*/ }
void Main(string[] args)
{
// Dependency Injection registration
var ioc = new WindsorContainer();
ioc.Register(
Component.For(typeof(IGetter<>)).ImplementedBy(typeof(Cache<>)),
Component.For(typeof(IGetter<>)).ImplementedBy(typeof(Logger<>)), // Decorators registered here are not being injected
Classes.FromThisAssembly()
.BasedOn(typeof(IGetter<>))
.WithServiceBase() // Getters for all sources are registered fine
);
var source1 = ioc.Resolve<IGetter<MailEvent>>();
source1.Query().Dump("Source 1 - \"Querying mails\"");
source1.Query().Dump("Source 1 - \"From cache\""); // Doesn't read from cache, instead it queries again
var source2 = ioc.Resolve<IGetter<FileEvent>>();
source2.Query().Dump("Source 2 - \"Querying files\"");
source2.Query().Dump("Source 2 - \"From cache\"");
var stats = ioc.Resolve<IGetter<StatisticsEvent>>(); // All implementations of IGetter and all implementations of IEvent must be successfully resovled
stats.Query().Dump("Statistics - \"Querying stats\"");
stats.Query().Dump("Statistics - \"From cache\"");
// This works, but we need Windsor to do it for us
// var manual = new Cache<MailEvent>(new Logger<MailEvent>(new MailGetter()));
// manual.Query().Dump("Manual - \"Querying mails\"");
// manual.Query().Dump("Manual - \"From cache\"");
}
您 运行 对 Castle Windsor 决定解决依赖关系的顺序和优先级的方式相当固执己见。
因为你有一个开放的泛型注册,或者更确切地说你有两个,而且还有大量的具体类型注册,所以它会优先考虑具体的实现。
关于如何解决这个问题有几种思路。
所有泛型装饰器的手动显式注册
ioc.Register(
Component.For<IGetter<MailEvent>>().ImplementedBy<Logger<MailEvent>>(),
Component.For<IGetter<FileEvent>>().ImplementedBy<Logger<FileEvent>>(),
Component.For<IGetter<StatisticsEvent>>().ImplementedBy<Logger<StatisticsEvent>>(),
Component.For<IGetter<MailEvent>>().ImplementedBy<Cache<MailEvent>>(),
Component.For<IGetter<FileEvent>>().ImplementedBy<Cache<FileEvent>>(),
Component.For<IGetter<StatisticsEvent>>().ImplementedBy<Cache<StatisticsEvent>>(),
Classes.FromThisAssembly()
.BasedOn(typeof(IGetter<>))
.WithServiceBase() // Getters for all sources are registered fine
);
缺点是很容易忘记注册另一个装饰器,但它可以解决问题。
拦截器(根据他们的 documentation)
您的里程可能会因这些而异,因为它们有效地代理了您的实施并在执行之前或之后采取行动。它们有点像装饰器,但不是纯粹意义上的装饰器。
根据已接受的答案 here.
手动实施ISubDependencyResolver