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

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

问题描述

我被这个SO问题触发关于 Autofac 的(.NET 4.0)协方差和逆变支持,现在我正在尝试实现类似的东西,但没有任何运气.

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.

我想要实现的是以这样的方式配置 Autofac,当我解析单个具体的 IEventHandler(为了演示使用 container.Resolve,但通常当然使用构造函数注入),Autofac 将返回一个 MultipleDispatchEventHandler,它包装了所有可从请求的处理程序分配的已注册事件处理程序.

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());

关于应用程序设计(如下所示),我希望返回一个 MultipleDispatchEventHandler,它包含一个 CustomerMovedEventHandler 和一个 NotifyStaffWhenCustomerMovedEventHandler.

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.

这是应用程序设计:

// 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) { ... }
}

这是MultipleDispatchEventHandler的定义,在Composition Root中定义:

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));
    }
}

这是我当前的配置:

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();

使用当前配置,应用程序在调用 Resolve 期间失败,但有以下异常:

With the current configuration, the application fails during the call to Resolve, with the following exception:

Autofac.Core.DependencyResolutionException:圆形组件检测到依赖:MultipleDispatchEventHandler'1[[SpecialCustomerMovedEvent]] ->IEventHandler'1[[SpecialCustomerMovedEvent]][] ->MultipleDispatchEventHandler'1[[SpecialCustomerMovedEvent]].

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 by @default.kramer.只是为了记录,因为链接的答案没有提供任何代码,并且由于涉及泛型类型,此场景的配置有点不直观:

+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天全站免登陆