2014-09-23 116 views
1

這裏是我的情況:溫莎登記通用命令/命令處理程序

public static class DomainCommandProcessor 
{ 
    public static void Dispatch<T>(T command) where T : IDomainCommand 
    { 
     var serviceLocator = ServiceLocator.Current; 

     var handler = serviceLocator.GetInstance<IDomainCommandHandler<T>>(); 
     if (handler != null) 
      handler.Handle(command); 
    } 
} 

public class FakeGenericCommand<T1, T2> : IDomainCommand 
{ 
    public FakeGenericCommand(T1 first, T2 second) 
    { 
     First = first; 
     Second = second; 
    } 

    public T1 First { get; private set; } 
    public T2 Second { get; private set; } 
} 

public class FakeGenericCommandHandler<T1, T2> : IDomainCommandHandler<FakeGenericCommand<T1, T2>> 
{ 
    public void Handle(FakeGenericCommand<T1, T2> command) 
    { 
     // something interesting 
    } 
} 

用法:

DomainCommandProcessor.Dispatch(new FakeGenericCommand<string, string>("hi", "there")) 

我不能讓溫莎註冊權。下面的作品非常適合我所有的非通用命令:

container.Register(Classes.FromAssemblyNamed(namespaceName) 
    .BasedOn(typeof(IDomainCommandHandler<>)) 
    .WithService.AllInterfaces() 
    .LifestyleTransient()); 

如果我直接註冊的每個可能的實現,它的工作原理,但顯然是次優:

container.Register(
    Component.For<IDomainCommandHandler<FakeGenericCommand<string, string>>>() 
     .UsingFactoryMethod(input => new FakeGenericCommandHandler<string, string>()) 
     .LifestyleTransient()); 

建議?

+0

由於您正在使用DI庫,是否有任何令人信服的理由讓您訴諸服務位置而不是使用依賴注入?將這個靜態'DomainCommandProcessor'比注入需要它的組件的'IDomainCommandProcessor'有什麼優勢? – Steven 2014-09-23 19:18:45

回答

1

你在這裏什麼是需要一個typed factory的教科書案例:我answered,我描述瞭如何使用它


這個答案在很大程度上受到啓發this article一個問題。

註冊所有的處理程序

container.Register(Classes.FromAssemblyInThisApplication() 
    .BasedOn<IDomainCommandHandler>() 
    .WithServiceAllInterfaces()); 

聲明一個工廠接口,將返回的處理程序命令

public interface IDomainCommandHandlerFactory 
{ 
    IDomainCommandHandler[] GetHandlersForCommand(IDomainCommand command); 
} 

您需要在命令類型鏈接到處理程序,你可以做一個自定義選擇器:

public class HandlerSelector:ITypedFactoryComponentSelector 
{ 
    public TypedFactoryComponent SelectComponent(MethodInfo method, Type type, object[] arguments) 
    { 
     var message = arguments[0]; 
     var handlerType = typeof(IDomainCommandHandler<>).MakeGenericType(message.GetType()); 
     return new TypedFactoryComponentCollection(handlerType.MakeArrayType(), new Arguments(arguments)); 
    } 
} 

然後告訴溫莎你想要一個工廠將返回一個IDomainCommandHandler<T>。不要爲工廠編寫任何代碼。

container.AddFacility<TypedFactoryFacility>(); 
container.Register(Component.For<ITypedFactoryComponentSelector>().ImplementedBy<HandlerSelector>()); 
container.Register(Component.For<IDomainCommandHandlerProvider>().AsFactory()); 

您現在可以使用工廠來檢索您的處理程序命令

var provider = container.Resolve<IDomainCommandHandlerFactory>(); 
var msg = new Type2Message(); 
var msgHandler = provider.GetHandlersForCommand(msg.MessageType); 

請注意,本例中的處理程序沒有運行對命令本身,但有一個Execute功能。如果你想返回關閉的通用對象,你需要在解析後進行轉換,因爲你不能從一個方法返回不同的類型。

我建議您閱讀原文,因爲它還包含有關生活方式,組件釋放和其他有趣的點的其他信息。


這裏我用了,我指定的請求,併爲通用組件

protected override Type GetComponentType(MethodInfo method, object[] arguments) 
{ 
    var request = arguments[0].GetType(); 
    var response = arguments[1] as Type; 
    var handlerType = typeof(IHandlerOf<,>).MakeGenericType(request, response); 
    return handlerType; 
} 

這裏響應請求的選擇的一個例子是調用工廠的結果(T是請求,R響應)

var handler = handlerFactory.GetHandler<T>(input, typeof(R)); 
var requestType = input.GetType(); 
var responseType = typeof(R); 
var handlerType = typeof(IHandlerOf<,>).MakeGenericType(requestType, responseType); 
r = (R)handlerType.GetMethod("Handle").Invoke(handler, new object[] { input }); 
+0

我的命令處理程序是通用的,它看起來像在你的例子中,它們不是。 TypedFactoryComponentCollection也無法解析,您是否使用最新的Windsor版本? – agartee 2014-09-25 12:54:03

+0

IDomainCommandHandlerFactory不處理通用命令處理程序 – agartee 2014-09-25 13:14:36

+0

的確,這就是我所指出的。如果返回通用命令處理程序,則需要在檢索命令處理程序後進行一些反射,以便將其稱爲通用方法,因爲工廠無法返回不同的封閉通用類型。 – samy 2014-09-25 13:22:28