我有一个获取数据的接口IGetter<IEvent>
,它有几个实现(每个实现从其他类型的源获取数据)。此接口是通用的,因为它的实现可以返回不同类型的事件(SourceEvent
和StatisticsEvent
,但都基于IEvent
接口)。
这是一个示例代码(隐藏的详细信息使帖子更短 - 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\"");
}
答案 0 :(得分:0)
你正在以相当自以为是的方式遇到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
的实施。