2015-05-04 159 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>>() 

這樣可能不是最好的