2015-05-04 141 views
0

喜的所有事件处理一些我能怎么找不到回答这个问题: 我有事件处理程序ALA:Autofac解决抽象基类

public class MyEvenHandler : EventHandler<MyEvent> 

如果事件处理程序是一个抽象类

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

...

​​

现在我要解决所有的事件处理器,并用messageDispatcher类

var handlers = e.Context.Resolve<IEnumerable<IEventHandler<IDomainEvent>>>().ToList(); 

var handlers2 = e.Context.Resolve<IEnumerable<IEventHandler<PolicyCreated>>>().ToList(); 

处理程序变量为空注册它们... handlers2正确解析。不过,我想解决genericly的所有处理

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

总结目标:

  1. 使用汇编扫描
  2. 决心实现IEnumerable的EventHandler

回答

1

要投射MyEvenHandlerIEventHandler<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应该如何执行它?Ë期待MyEvent,而不是一个MyEvent2

如果你希望所有的事件处理器的列表,你将不得不推出一个基本接口

public interface IEventHandler 
{ 
    Boolean Handles(IDomainEvent @event); 
} 
public interface IEventHandler<TEvent> : IEventHandler 
    where TEvent : IDomainEvent 
{ 
    void Handle(TEvent @event); 
    Task HandleAsync(TEvent @event); 
} 

并注册事件处理器为IEventHandler

ContainerBuilder builder = new ContainerBuilder(); 
builder.RegisterAssemblyTypes(typeof(Program).Assembly) 
     .AsClosedTypesOf(typeof(IEventHandler<>)) 
     .As<IEventHandler>(); 

使用此注册,您将能够解决IEventHandlerIEventHandler<MyEvent>

var genericHandlers = container.Resolve<IEnumerable<IEventHandler>>(); 
var handlers = container.Resolve<IEnumerable<IEventHandler<MyEvent>>>(); 

顺便说一句,而不必对IEnumerable<IEventHandler>的依赖,messageDispatcher可能对ILifetimeScope的依赖性,当它需要事件处理器,它能够解决这些问题:

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,y您必须使用out修饰符将IEventHandler<TEvent>转换为协变接口(有关更多信息,请参阅out (Generic Modifier) (C# Reference))。

public interface IEventHandler<out TEvent> 
    where TEvent : DomainEventBase 
{ } 

利用这一点,CLR将能够投MyEventHandlerIEventHandler<DomainEventBase>

然后,你必须注册为IEventHandler<DomainEventBase>

builder.RegisterAssemblyTypes(typeof(Program).Assembly) 
     .As<IEventHandler<DomainEventBase>>(); 

现在可以使用

container.Resolve<IEnumerable<IEventHandler<DomainEventBase>>>() 

顺便说让所有的事件处理器告诉Autofac你的类型是IEventHandler<DomainEventBase>时,您的情况下不需要ContravariantRegistrationSource

+0

Thx回答! IEventHandler在其Handle方法中将TEvent作为输入参数,因此它不能被声明为协变。我已经添加了完整的声明 –

+0

@ChristianJohansen查看我的编辑。顺便说一句,你可以分享你的messageDispatcher吗?可能有事要做 –

+0

当然!我已经添加了messageDispathcer(EventDispatcher)的代码。我目前的工作是注册并解析为简单的非通用接口IEventHandler,将我的自我限制为仅使用接口。 –

0

1,创建一个空的接口不通用

public interface IEventHandler{} 

2,您IEventHandler应该实现此接口

IEventHandler<TEvent>:IEventHandler 

3,尽量化解采用此接口

e.Context.Resolve<IEnumerable<IEventHandler>>() 

这样可能不是最好的