2014-02-14 23 views
0

这个概念非常流行,但我还没有找到答案。我该如何更好地使用Ninject IOC

我有以下的阶层结构

public interface IMessage 
{ 
} 

public class MessageA : IMessage 
{ 
} 

public class MessageB : IMessage 
{ 
} 

public interface IMessageHandler<T> where T : IMessage 
{ 
    void Handle(TMessage message); 
} 

public interface MessageAHandler : IMessageHandler<MessageA> 
{ 
} 

public interface MessageBHandler : IMessageHandler<MessageB> 
{ 
} 

public class MessageProcessor 
{ 
    public void Process(IMessage) 
    { 
     if (IMessage is MessageA) 
     { 
      // handler for messageA has to be invoked 
     } 
     else if (IMessage is MessageB) 
     { 
      // handler for messageB has to be invoked 
     } 
    } 
} 

现在我使用Ninject和dooing我绑定像

Bind<IMessageHandler<MessageA>>.To<MessageAHandler>(); 
Bind<IMessageHandler<MessageB>>.To<MessageBHandler>(); 

我想以某种方式做所有的绑定魔法结合模块中选择处理程序。 MessageProcessor类应该只是通过来调用它来处理消息。

这是什么东西是以及如何在绑定模块中完成是我无法弄清楚的。有人可以帮助!

感谢

+0

你怎么在'MessageProcessor'类中注入类型? –

+0

使用ninject的构造函数注入。代码已被省略由于NDA限制 – user205892

回答

2

使用ninject约定延长https://github.com/ninject/ninject.extensions.conventions,选择所有类型从typeof(IMessageHandler<>)继承,然后使用自定义IBindingGenerator实现。例如:

 this.Kernel.Bind(x => x 
      .FromThisAssembly() 
      .IncludingNonePublicTypes() 
      .SelectAllClasses() 
      .InheritedFrom(typeof(IMessageHandler<>)) 
      .BindWith<MessageHandlerBindingGenerator>()); 

,在键合生成器使用反射来创建特定接口类型IMessageHandler<XYZ>和使用它像this.Kernel.Bind(interfaceType)。为了(类型)。

如果您愿意,我可以提供一个完整的实现。

好吧,我试图保持尽可能简单,如果有什么更复杂,你真的需要,那么请告诉我:

public interface IMessage { } 
public class MessageA : IMessage { } 
public class MessageB : IMessage { } 

public interface IMessageHandler<T> 
    where T : IMessage 
{ 
    void Handle(T message); 
} 

public class MessageHandlerA : IMessageHandler<MessageA> 
{ 
    public void Handle(MessageA message) 
    { 
     Console.WriteLine("Message A handled"); 
    } 
} 

public class MessageHandlerB : IMessageHandler<MessageB> 
{ 
    public void Handle(MessageB message) 
    { 
     Console.WriteLine("Message B handled"); 
    } 
} 

public class MessageProcessor 
{ 
    private static readonly MethodInfo GenericProcessMethod = typeof(MessageProcessor).GetMethod("ProcessGeneric"); 

    private readonly IResolutionRoot resolutionRoot; 

    public MessageProcessor(IResolutionRoot resolutionRoot) 
    { 
     this.resolutionRoot = resolutionRoot; 
    } 

    public void Process(IMessage message) 
    { 
     GenericProcessMethod.MakeGenericMethod(message.GetType()) 
      .Invoke(this, new object[] { message }); 
    } 

    public void ProcessGeneric<TMessage>(TMessage message) 
     where TMessage : IMessage 
    { 
     var handler = this.resolutionRoot.Get<IMessageHandler<TMessage>>(); 
     handler.Handle(message); 
    } 
} 

public class Test 
{ 
    private readonly IKernel kernel; 

    public Test() 
    { 
     this.kernel = new StandardKernel(); 

     this.kernel.Bind(x => x 
      .FromThisAssembly() 
      .IncludingNonePublicTypes() 
      .SelectAllClasses() 
      .InheritedFrom(typeof(IMessageHandler<>)) 
      .BindSingleInterface()); 
    } 

    [Fact] 
    public void IntegrationTest() 
    { 
     var messageProcessor = this.kernel.Get<MessageProcessor>(); 

     messageProcessor.Process(new MessageA()); 
     messageProcessor.Process(new MessageB()); 
    } 
} 

(在[事实]属性来源于xUnit的,我用运行测试。)

我遗漏了interface IMessageAHandler : IMessageHandler<MessageA>等接口,你真的需要它们吗?他们让事情变得更加复杂。无论是对于绑定生成器还是确定消息处理器需要使用的类型都会变得更加复杂。

+0

这将是真棒 – user205892