嗨有些我怎么找不到这个问题的答案: 我有事件处理程序ala:
public class MyEvenHandler : EventHandler<MyEvent>
其中EventHandler是一个抽象类
public abstract class EventHandler<TEvent> : IEventHandler<TEvent>
where TEvent : IDomainEvent
和
public interface IEventHandler<in TEvent> : IEventHandler where TEvent : IDomainEvent
{
bool Handles(IDomainEvent @event);
void Handle(TEvent @event);
Task HandleAsync(TEvent @event);
}
我注册了这样的autofac:
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
...
builder.RegisterAssemblyTypes(commandsAssemblies)
.AsClosedTypesOf(typeof(EventHandler<>))
.AsImplementedInterfaces()
.InstancePerRequest();
现在我想要解析所有的事件处理程序并使用messageDispatcher类
注册它们var handlers = e.Context.Resolve<IEnumerable<IEventHandler<IDomainEvent>>>().ToList();
var handlers2 = e.Context.Resolve<IEnumerable<IEventHandler<PolicyCreated>>>().ToList();
handlers变量为空... handlers2正确解析。但我想通用地解决所有处理程序
messageDispatcher(eventDispathcer)如下所示:
public class EventDispatcher : IEventDispatcher
{
private readonly IList<IEventHandler> _eventHandlers = new List<IEventHandler>();
public virtual void RegisterEventHandler(IEventHandler eventHandler)
{
_eventHandlers.Add(eventHandler);
}
public virtual IMessageResults Publish<TEvent>(TEvent @event) where TEvent : IDomainEvent
{
var result = new MessageResults();
var handlers = _eventHandlers;
if (handlers == null)
{
Trace.WriteLine(String.Format("No event handlers for event {0} ", typeof(TEvent)));
result.AddResult(new MessageResult(true));
return result;
}
foreach (var eventHandler in handlers.Where(h => h.Handles(@event as IDomainEvent)))
{
eventHandler.Handle(@event);
}
return result;
}
public int EventHandlerCount
{
get
{
return _eventHandlers.Count();
}
}
}
总结目标:
答案 0 :(得分:1)
您想将MyEvenHandler
投射到IEventHandler<IDomainEvent>
如果我们尝试以下代码:
MyEventHandler handler = new MyEventHandler();
IEventHandler<IDomainEvent> e = (IEventHandler<IDomainEvent>)handler;
CLR将抛出InvalidCastException
,因为IEventHandler<TDomainEvent>
不是协变的。如果CLR允许这种转换,则意味着将编译以下代码:
MyEventHandler handler = new MyEventHandler();
IEventHandler<IDomainEvent> e = (IEventHandler<IDomainEvent>)handler;
e.Handle(new MyEvent2());
CLR应如何执行它? e期望MyEvent
而不是MyEvent2
如果您需要所有eventHandler的列表,则必须引入基本接口
public interface IEventHandler
{
Boolean Handles(IDomainEvent @event);
}
public interface IEventHandler<TEvent> : IEventHandler
where TEvent : IDomainEvent
{
void Handle(TEvent @event);
Task HandleAsync(TEvent @event);
}
将eventHandlers注册为IEventHandler
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.AsClosedTypesOf(typeof(IEventHandler<>))
.As<IEventHandler>();
使用此注册,您将能够解析IEventHandler
和IEventHandler<MyEvent>
var genericHandlers = container.Resolve<IEnumerable<IEventHandler>>();
var handlers = container.Resolve<IEnumerable<IEventHandler<MyEvent>>>();
顺便说一下,IEnumerable<IEventHandler>
可能依赖于messageDispatcher
,而不是依赖于ILifetimeScope
,而且当它需要eventHandlers时,它将能够解决它们:
public class EventDispatcher
{
private readonly ILifetimeScope _scope;
public EventDispatcher(ILifetimeScope scope)
{
this._scope = scope;
}
public virtual IMessageResults Publish<TEvent>(TEvent @event) where TEvent : IDomainEvent
{
var result = new MessageResults();
var handlers = this._scope.Resolve<IEnumerable<IEventHandler<TEvent>>>().ToList();
if (!handlers.Any())
{
Trace.WriteLine(String.Format("No event handlers for event {0} ", typeof(TEvent)));
result.AddResult(new MessageResult(true));
}
else
{
foreach (var eventHandler in handlers.Where(h => h.Handles(@event as IDomainEvent)))
{
eventHandler.Handle(@event);
}
}
return result;
}
public int EventHandlerCount
{
get
{
// not tested
var handlerCount = this._scope.ComponentRegistry
.Registrations
.Where(r => r.Services
.OfType<IServiceWithType>()
.Any(swt => swt.ServiceType.IsGenericType
&& swt.ServiceType.GetGenericTypeDefinition() == typeof(IEventHandler<>)))
.Count();
return handlerCount;
}
}
}
编辑:这个答案是在使用完整界面声明进行编辑之前的
如果IEventHandler<TEvent>
不接受任何TEvent
方法,则必须使用IEventHandler<TEvent>
修饰符将out
转换为协变界面(请参阅{{3} }了解更多信息)。
public interface IEventHandler<out TEvent>
where TEvent : DomainEventBase
{ }
使用此功能,CLR将能够MyEventHandler
投射到IEventHandler<DomainEventBase>
。
然后,您必须通过将其注册为IEventHandler<DomainEventBase>
IEventHandler<DomainEventBase>
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.As<IEventHandler<DomainEventBase>>();
您现在可以使用
获取所有的eventHandlercontainer.Resolve<IEnumerable<IEventHandler<DomainEventBase>>>()
顺便说一下,在您的情况下不需要ContravariantRegistrationSource
。
答案 1 :(得分:0)
1,创建一个没有通用
的空接口public interface IEventHandler{}
2,你的IEventHandler应该实现这个接口
IEventHandler<TEvent>:IEventHandler
3,尝试解决使用此界面
e.Context.Resolve<IEnumerable<IEventHandler>>()
这种方式可能不是最好的