2014-02-14 3 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>()); 

И в Binding использования Builder отражение, чтобы создать определенный тип интерфейса 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

Смежные вопросы