我如何使用Ninject IOC更好地做到这一点 [英] How can i do this better using Ninject IOC

查看:73
本文介绍了我如何使用Ninject IOC更好地做到这一点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个概念很流行,但是我还没有找到答案.

the concept is quite popular but I have not found the answer yet.

我具有以下课程结构

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并像我的绑定那样做

Now I am using Ninject and dooing my bindings like

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

我想以某种方式在绑定模块中执行所有绑定魔术,以选择处理程序.应该将MessageProcessor类传递给某物,然后调用它来处理消息.

I want to do all the binding magic somehow in the binding module for choosing the handler. MessageProcessor class should just be passed something which it calls to handle the message.

这个东西是什么,以及它如何在绑定模块中完成,这是我无法弄清楚的.有人可以帮忙吗!

What this something is and how it can be done in the binding module is what i cannot figure out. Can someone please help!

谢谢

推荐答案

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

Use the ninject conventions extension https://github.com/ninject/ninject.extensions.conventions, select all types inheriting from typeof(IMessageHandler<>) and then use a custom IBindingGenerator implementation. For example:

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

然后在绑定生成器中使用反射来创建特定的接口类型IMessageHandler<XYZ>并像这样使用它.Kernel.Bind(interfaceType).To(type).

And at the Binding Builder use reflection to create the specific interface type IMessageHandler<XYZ> and use it like this.Kernel.Bind(interfaceType).To(type).

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

I can provide a complete implementation if you wish.

好吧,我试图使它尽可能简单,如果您确实需要更复杂的东西,那么请告诉我:

Okay i tried to keep it as simple as possible, if there is anything more complicated that you really need, then please tell me:

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,我用它来运行测试.)

(the [Fact] attribute comes from xUnit which i use to run the test.)

我遗漏了interface IMessageAHandler : IMessageHandler<MessageA>等接口,您真的需要它们吗?它们使事情变得更加复杂.对于绑定生成器来说,要确定消息处理器需要使用的类型会变得更加复杂.

I left out the interface IMessageAHandler : IMessageHandler<MessageA> etc. interfaces, do you really need them? They make things more complicated. Either for the binding generator or the it gets more complicated to determine the type the message processor needs to use.

这篇关于我如何使用Ninject IOC更好地做到这一点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆