Autofac:隐藏多个逆变实现一个组合的背后 [英] Autofac: Hiding multiple contravariant implementations behind one composite
问题描述
我被这太问题引发关于(.NET 4.0)用于Autofac协变和逆变支持,现在我想达到类似的东西,但没有任何运气。
我想实现的就是配置Autofac在这样的方式,当我解决一个具体的 IEventHandler< TEvent>
(示范使用 container.Resolve
,但通常的过程中使用构造函数注入的缘故),Autofac将返回我一个 MultipleDispatchEventHandler< TEvent>
用于包装所有注册的事件处理是从请求的处理程序分配
在换句话说,当我写这篇文章:
<预类=郎-CS prettyprint-覆盖>
VAR处理器=容器
.GetInstance< IEventHandler< CustomerMovedEvent>>();
handler.Handle(新CustomerMovedEvent());
对于应用程序设计(如下),我期望一个 MultipleDispatchEventHandler< CustomerMovedEvent>
将返回包装了一个 CustomerMovedEventHandler
和 NotifyStaffWhenCustomerMovedEventHandler
。
下面是应用程序设计:
<预类=郎-CS prettyprint-覆盖>
//活动:
公共类CustomerMovedEvent {}
公共类CustomerMovedAbroadEvent:CustomerMovedEvent {}
公共类SpecialCustomerMovedEvent:CustomerMovedEvent {}
//事件处理程序定义(注意'在'关键字):
公共接口IEventHandler<在TEvent>
{
无效手柄(TEvent E);
}
//事件处理程序实现:
公共类CustomerMovedEventHandler
:IEventHandler< CustomerMovedEvent>
{
公共无效手柄(CustomerMovedEvent E){...}
}
公共类NotifyStaffWhenCustomerMovedEventHandler
:IEventHandler< CustomerMovedEvent>
{
公共无效手柄(CustomerMovedEvent E){...}
}
公共类CustomerMovedAbroadEventHandler
:IEventHandler< CustomerMovedAbroadEvent>
{
公共无效手柄(CustomerMovedAbroadEvent E){...}
}
这是定义的 MultipleDispatchEventHandler< TEvent>
,在Composition根定义的:
//复合包装可能是多个处理程序。
公共类MultipleDispatchEventHandler< TEvent>
:IEventHandler< TEvent>
{
私人的IEnumerable< IEventHandler< TEvent>>处理程序;
公共MultipleDispatchEventHandler(
IEnumerable的< IEventHandler< TEvent>>处理程序)
{
this.handlers =处理程序;
}
公共无效手柄(TEvent E)
{
this.handlers.ToList()的ForEach(H => h.Handle(E))。 ;
}
}
这是我目前的配置:
<预类=郎-CS prettyprint-覆盖>
VAR建设者=新ContainerBuilder();
//注意使用ContravariantRegistrationSource(这是
//在Autofac的最新版本中提供)的。
builder.RegisterSource(新ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof运算(IEventHandler<>)大会。)
.AsClosedTypesOf(typeof运算(IEventHandler<>));
//更新:我注册这个去年一样克莱默建议。
builder.RegisterGeneric(typeof运算(MultipleDispatchEventHandler<>))
。至于(typeof运算(IEventHandler<>))。SingleInstance();
VAR容器= builder.Build();
通过当前的配置,应用程序调用解析过程中失败code>,与以下异常:
Autofac.Core.DependencyResolutionException:圆形组件
依赖检测:
MultipleDispatchEventHandler'1 [SpecialCustomerMovedEvent] - >
IEventHandler'1 [SpecialCustomerMovedEvent] [] - >
MultipleDispatchEventHandler'1 [SpecialCustomerMovedEvent]
< /块引用>
现在的问题当然是:我怎么能解决的配置(或设计),以支持该
解决方案+1
IEventRaiser< T>
通过@ default.kramer。只是为了记录在案,因为链接的答案不提供任何代码,此方案的配置比直观的,因为所涉及的泛型类型的少一点:builder.RegisterSource(新ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(...)
。至于(T => t.GetInterfaces()
。凡(I => i.IsClosedTypeOf(typeof运算(IEventHandler< ;>)))
。选择(I =>新建KeyedService(经理人,我)));
builder.RegisterGeneric(typeof运算(MultipleDispatchEventHandler<>))
。至于(typeof运算(IEventHandler<>))
.WithParameter(
(PI,C )=> pi.Name ==处理程序,
(PI,C)=> c.ResolveService(
新KeyedService(经理人,pi.ParameterType)));
I was triggered by this SO question about (.NET 4.0) covariance and contravariance support for Autofac, and now I'm trying to achieve something similar, but without any luck.
What I am trying to achieve is configure Autofac in such way that when I resolve a single concrete
IEventHandler<TEvent>
(for the sake of demonstration usingcontainer.Resolve
, but normally of course using constructor injection), Autofac will return me aMultipleDispatchEventHandler<TEvent>
that wraps all registered event handlers that are assignable from the requested handler.In other words, when I write this:
var handler = container .GetInstance<IEventHandler<CustomerMovedEvent>>(); handler.Handle(new CustomerMovedEvent());
With respect to the application design (given below), I'd expect a
MultipleDispatchEventHandler<CustomerMovedEvent>
to be returned that wraps both aCustomerMovedEventHandler
and aNotifyStaffWhenCustomerMovedEventHandler
.Here is the application design:
// Events: public class CustomerMovedEvent { } public class CustomerMovedAbroadEvent : CustomerMovedEvent { } public class SpecialCustomerMovedEvent : CustomerMovedEvent { } // Event handler definition (note the 'in' keyword): public interface IEventHandler<in TEvent> { void Handle(TEvent e); } // Event handler implementations: public class CustomerMovedEventHandler : IEventHandler<CustomerMovedEvent> { public void Handle(CustomerMovedEvent e) { ... } } public class NotifyStaffWhenCustomerMovedEventHandler : IEventHandler<CustomerMovedEvent> { public void Handle(CustomerMovedEvent e) { ... } } public class CustomerMovedAbroadEventHandler : IEventHandler<CustomerMovedAbroadEvent> { public void Handle(CustomerMovedAbroadEvent e) { ... } }
This is the definition of the
MultipleDispatchEventHandler<TEvent>
, defined in the Composition Root:// A composite wrapping possibly multiple handlers. public class MultipleDispatchEventHandler<TEvent> : IEventHandler<TEvent> { private IEnumerable<IEventHandler<TEvent>> handlers; public MultipleDispatchEventHandler( IEnumerable<IEventHandler<TEvent>> handlers) { this.handlers = handlers; } public void Handle(TEvent e) { this.handlers.ToList().ForEach(h => h.Handle(e)); } }
This is my current configuration:
var builder = new ContainerBuilder(); // Note the use of the ContravariantRegistrationSource (which is // available in the latest release of Autofac). builder.RegisterSource(new ContravariantRegistrationSource()); builder.RegisterAssemblyTypes(typeof(IEventHandler<>).Assembly) .AsClosedTypesOf(typeof(IEventHandler<>)); // UPDATE: I'm registering this last as Kramer suggests. builder.RegisterGeneric(typeof(MultipleDispatchEventHandler<>)) .As(typeof(IEventHandler<>)).SingleInstance(); var container = builder.Build();
With the current configuration, the application fails during the call to
Resolve
, with the following exception:Autofac.Core.DependencyResolutionException: Circular component dependency detected: MultipleDispatchEventHandler'1[[SpecialCustomerMovedEvent]] -> IEventHandler'1[[SpecialCustomerMovedEvent]][] -> MultipleDispatchEventHandler'1[[SpecialCustomerMovedEvent]].
Now the question is of course: how can I fix the configuration (or the design) to support this?
解决方案+1 for
IEventRaiser<T>
by @default.kramer. Just for the record, since the linked answer doesn't provide any code, and the configuration for this scenario is a bit less than intuitive because of the generic types involved:builder.RegisterSource(new ContravariantRegistrationSource()); builder.RegisterAssemblyTypes(...) .As(t => t.GetInterfaces() .Where(i => i.IsClosedTypeOf(typeof(IEventHandler<>))) .Select(i => new KeyedService("handler", i))); builder.RegisterGeneric(typeof(MultipleDispatchEventHandler<>)) .As(typeof(IEventHandler<>)) .WithParameter( (pi, c) => pi.Name == "handlers", (pi, c) => c.ResolveService( new KeyedService("handler", pi.ParameterType)));
这篇关于Autofac:隐藏多个逆变实现一个组合的背后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!