2011-01-19 74 views
8

我有以下幾點:StructureMap對所有可能的具體實現註冊泛型類型

public interface ICommand { } 
public class AddUser : ICommand 
{ 
    public string Name { get; set; } 
    public string Password { get; set; } 
} 

public interface ICommandHandler<T> : IHandler<T> where T : ICommand 
{ 
    void Execute(T command); 
} 

public class AddUserHandler : ICommandHandler<AddUser> 
{ 
    public void Execute(AddUser command) 
    { 
     Console.WriteLine("{0}: User added: {1}", GetType().Name, command.Name); 
    } 
} 

public class AuditTrailHandler : ICommandHandler<ICommand> 
{ 
    public void Execute(ICommand command) 
    { 
     Console.WriteLine("{0}: Have seen a command of type {1}", GetType().Name, command.GetType().Name); 
    } 
} 

我想用掃描註冊ICommandHandler <>讓我得到以下類型的容器:

  • ICommandHandler<AddUser>與具體類型AddUserHandler
  • ICommandHandler<AddUser>與具體類型​​

我已經試過這與IRegistrationConvention的實施,並在一個點上,我有它的工作,但我不能讓我的腦袋周圍如何做到這一點。

我們的目標是能夠執行多個處理程序特定的ICommand實現像這樣:

// A method in CommandDispatcher 
public void SendCommand<T>(T command) where T : ICommand { 
    var commandHandlers = container.GetAllInstances<ICommandHandler<T>>(); 
    foreach (var commandHandler in commandHandlers) { 
     commandHandler.Execute(command);  
    } 
} 

我想AuditTrailHandler<ICommand>執行的ICommand的所有具體實現,因此需要將它們註冊爲所有ICommand類型。

次要目標是如果我可以將一個ICommandHandlers<ICommand>集合注入到我的CommandDispatcher而不是容器中,但我認爲這對我現在的結構是不可能的。如果你有任何想法,證明我錯了。

編輯 - 解決

我添加了一個非通用接口,我的通用接口實現,然後我還添加了一個抽象CommandHandler<T>所以我沒有實現CanHandle或執行(對象)的所有方法我的處理程序。

這是工作結構:

public interface ICommandHandler 
{ 
    void Execute(object command); 
    bool CanHandle(ICommand command); 
} 

public interface ICommandHandler<T> : ICommandHandler, IHandler<T> where T : ICommand 
{ 
    void Execute(T command); 
} 

public abstract class AbstractCommandHandler<T> : ICommandHandler<T> where T : ICommand 
{ 
    public abstract void Execute(T command); 
    public void Execute(object command) 
    { 
     Execute((T)command); 
    } 

    public virtual bool CanHandle(ICommand command) 
    { 
     return command is T; 
    } 
} 

而且因爲這原本是一個StructureMap的問題,這裏是掃描到補充一點:

Scan(x => 
     { 
      x.AssemblyContainingType<MyConcreteHandler>(); 
      x.IncludeNamespaceContainingType<MyConcreteHandler>(); 
      x.AddAllTypesOf<ICommandHandler>(); 
      x.WithDefaultConventions(); 
     }); 

這使我能夠在注入一個IEnumerable我的CommandDispatcher並執行如下:

public void SendCommand<T>(T command) where T : ICommand 
    { 
     var commandHandlersThatCanHandle = commandHandlers.Where(c => c.CanHandle(command)); 
     foreach (var commandHandler in commandHandlersThatCanHandle) 
     { 
      commandHandler.Execute(command);  
     } 
    } 

這使我能夠執行Com MandHandlers支持AddUser(就像AddUserHandler),但我也能夠執行支持ICommand的處理程序(如AuditTrailHandler)。

這很甜!

回答

4

要將所有命令處理程序注入到命令調度程序中,請創建一個新的非通用ICommandHandler接口,該接口從ICommandHandler<T>派生而來。它有一個Execute方法,它接受一個對象。缺點是,你的每一個命令處理程序必須實現該方法來調用輸入過載:

public class AddUserHandler : ICommandHandler<AddUser> 
{ 
    public void Execute(object command) 
    { 
     Execute((AddUser)command); 
    } 
    public void Execute(AddUser command) 
    { 
     Console.WriteLine("{0}: User added: {1}", GetType().Name, command.Name); 
    } 
} 

這將使你的指揮調度會對IEnumerable<ICommandHandler>構造函數依賴,這StructureMap將自動填充。

在SendCommand中,您有兩種獲取相應處理程序的方法。基於A型簡單的過濾器:

commandHandlers.OfType<ICommandHandler<T>> 

或添加CanHandle(object command)ICommandHandler接口:

commandHandlers.Where(x => x.CanHandle(command)) 

第二種方法需要更多的代碼,但是允許您連接處理給你多一點靈活性不僅僅是類型。這可能會使您的​​始終返回trueCanHandle更容易解決您的第一個問題。

+0

太棒了! 我以前有過CanHandle方法,但是因爲我認爲StructureMap魔術可以幫我做到這一點,所以將其刪除。 我甚至進一步做了一個抽象的CommandHandler ,並將它放在泛型接口和具體類之間,這樣我就可以從CanHandle方法中受益,而無需在所有派生類中實現它。 真棒,謝謝! – 2011-01-19 16:11:59

相關問題