【发布时间】:2011-08-21 15:04:08
【问题描述】:
this SO question 触发了我对 Autofac 的 (.NET 4.0) 协变和逆变支持,现在我正在尝试实现类似的东西,但没有任何运气。
我想要实现的是以这样的方式配置 Autofac,即当我解析单个具体的 IEventHandler<TEvent>(为了使用 container.Resolve 进行演示,但通常当然使用构造函数注入)时,Autofac 将返回给我一个MultipleDispatchEventHandler<TEvent> 包装了所有可从请求的处理程序分配的已注册事件处理程序。
换句话说,当我写这个时:
var handler = container
.GetInstance<IEventHandler<CustomerMovedEvent>>();
handler.Handle(new CustomerMovedEvent());
关于应用程序设计(如下所示),我希望返回一个包含CustomerMovedEventHandler 和NotifyStaffWhenCustomerMovedEventHandler 的MultipleDispatchEventHandler<CustomerMovedEvent>。
这是应用程序设计:
// 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<TEvent>的定义,在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 期间失败,以下情况除外:
Autofac.Core.DependencyResolutionException:循环组件 检测到依赖: MultipleDispatchEventHandler'1[[SpecialCustomerMovedEvent]] -> IEventHandler'1[[SpecialCustomerMovedEvent]][] -> MultipleDispatchEventHandler'1[[SpecialCustomerMovedEvent]]。
现在的问题当然是:如何修复配置(或设计)以支持此功能?
【问题讨论】:
-
我们是否需要使用 autofac 来解决这个问题?或者您只是想弄清楚各种 IoC 容器是如何解决这种特殊情况的?
-
@thekip:你可能已经看过我的问题历史了 :-)。虽然我很想知道如何使用 Castle Windsor、StructureMap 和 Unity 等容器来做到这一点,但我目前对 Autofac 感兴趣,因为该容器最近添加了对逆变的显式支持。我以后可能会针对这些容器添加问题,所以请不要为其他容器回答。当然,我知道如何使用 Simple Injector 来做到这一点;-)
-
当然,如果您将
IEventPublisher<TEvent>与IEventHandler<TEvent>分开,您的示例场景很容易解决。无论如何,这可能是一个好主意,这取决于您问谁 - 为事件发起者和事件消费者提供单独的界面可以降低耦合度。但是没有复合材料,我假设您对复合材料比四处走动的客户更感兴趣:) -
@default:你能更新/附加你的答案来告诉我这个吗?我很感兴趣。
标签: c# dependency-injection ioc-container autofac covariance