如何使用Ninject IOC更好地完成这项工作

时间:2014-02-14 12:49:20

标签: c# dependency-injection ninject

这个概念很受欢迎,但我还没有找到答案。

我有以下类结构

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并将我的绑定添加到

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

我想在绑定模块中以某种方式执行所有绑定魔法以选择处理程序。 MessageProcessor类应该只传递某些,它调用它来处理消息。

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

由于

1 个答案:

答案 0 :(得分: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>并像这样使用它.Kernel.Bind(interfaceType).To(type)。

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

好的,我尽量保持简单,如果你真的需要更复杂的东西,那么请告诉我:

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());
    }
}

([Fact]属性来自xUnit,我用它来运行测试。)

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