【问题标题】:How can i do this better using Ninject IOC如何使用 Ninject IOC 更好地做到这一点
【发布时间】:2014-02-14 12:49:19
【问题描述】:

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

我有以下类结构

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 类应该只传递 something 它调用来处理消息。

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

谢谢

【问题讨论】:

  • 你是如何在MessageProcessor 类上注入类型的?
  • 使用ninject进行构造函数注入。由于 NDA 限制,代码已被省略

标签: c# dependency-injection ninject


【解决方案1】:

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

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

并且在Binding Builder使用反射来创建具体的接口类型IMessageHandler&lt;XYZ&gt;,并像this.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&lt;MessageA&gt; 等接口,你真的需要它们吗?它们使事情变得更加复杂。对于绑定生成器,或者确定消息处理器需要使用的类型变得更加复杂。

【讨论】:

  • 那太好了
猜你喜欢
  • 2011-02-27
  • 1970-01-01
  • 2019-09-19
  • 2019-04-30
  • 2017-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多