Autofac:隐藏多个逆变实现一个组合的背后 [英] Autofac: Hiding multiple contravariant implementations behind one composite

查看:790
本文介绍了Autofac:隐藏多个逆变实现一个组合的背后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我被这太问题引发关于(.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();

通过当前的配置,应用程序调用解析,与以下异常:




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 using container.Resolve, but normally of course using constructor injection), Autofac will return me a MultipleDispatchEventHandler<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 a CustomerMovedEventHandler and a NotifyStaffWhenCustomerMovedEventHandler.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆