【问题标题】:Ninject 2.0 - binding to a object that uses the same interface more than once?Ninject 2.0 - 绑定到多次使用同一接口的对象?
【发布时间】:2011-01-24 16:11:01
【问题描述】:

考虑以下几点:

    public Something(IInterface concreteObjectOne, IInterface concreteObjectTwo) 
    {
        this.concreteObjectOne = concreteObjectOne;
        this.concreteObjectTwo = concreteObjectTwo;
    }

如何使用 Ninject 设置这种类型的绑定?我会尝试用谷歌搜索这个词,但由于我不确定这叫什么,所以我不能,也无法在 Wiki 上找到任何关于此的内容。

编辑

我相信这称为基于约定的绑定,如 here 所述。但是,此文档适用于 1.0 版,而 2.0 版没有 Only 方法。我希望在没有属性的情况下实现这一点 - 使用名称约定或类似的东西。

【问题讨论】:

    标签: c# binding ioc-container ninject


    【解决方案1】:

    如果允许我提供一些通用的,而不是特定于 Ninject 的指导,我建议您稍微重新考虑您的设计。当前的构造函数是模糊的,因为它没有提供关于 IInterface 的哪个实现去哪里的指导 - 我意识到这只是你的真实 API 的模型,而真实的 API 可能会提供更多帮助以恰当命名的参数形式对人类开发者来说,像 DI 容器这样的机器无法推断出正确的用法。

    许多 DI 容器提供了一些解决这种模糊性的方法,例如通过提供可用于将名称(元数据)与每个依赖项关联起来的属性。 AFAIR,Ninject 有Inject 属性...

    但是,请考虑几个替代方案:

    第一种选择是将两个相似的接口实例封装在一个参数对象中,如下所示:

    public interface IParameterObject
    {
        IInterface ObjectOne { get; }
    
        IInterface ObjectTwo { get; }
    }
    

    您现在可以将构造函数更改为采用 IParameterObject 实例而不是两个接口实例本身。

    public Something(IParameterObject po)
    {
        this.concreteObjectOne = po.ObjectOne;
        this.concreteObjectTwo = po.ObjectTwo;
    }
    

    这意味着您可以将 IParameterObject 的配置推送到Composition Root

    另一种值得思考的方法是,将具有两个实例的情况视为具有任意数量实例的更一般设计的特殊情况是否有意义。这可能并不总是如此,但如果是这样,您可以将构造函数更改为:

    public Something(IEnumerable<IInterface> objects)
    

    我个人更喜欢上述任何建议,而不是使用特定 Ninject 功能的任何建议,因为它迫使我使 API 总体上更明确,因此更具可读性和可维护性。

    【讨论】:

    • @马克。你昨天回答(再次感谢)让我使用工厂,以便为我的可插入算法使用策略设计模式。有问题的工厂现在采用两个具体对象,但是当我使用策略模式时,它们都是相同的接口。通常没有 IOC,我会编写这样的代码并手动连接依赖项。它还使单元测试变得容易。虽然你的建议会起作用,但我不知何故觉得它是不必要的。在 2.0 中,除了简单的绑定之外,我似乎找不到正确的方法。
    • 很公平 - 很高兴您找到了解决方案 :)
    【解决方案2】:

    除了使用“Only”方法外,文章还提出了另一种解决方案,为注入的对象指定不同的属性。

    示例:

    public class ObjectOneAttribute : Attribute
    {
    
    }  
    public class ObjectTwoAttribute : Attribute
    {
    
    }
    

    然后

    public Something([ObjectOneAttribute] IInterface concreteObjectOne, [ObjectTwoAttribute] IInterface concreteObjectTwo) 
        {
            this.concreteObjectOne = concreteObjectOne;
            this.concreteObjectTwo = concreteObjectTwo;
        }
    

    当你想将接口绑定到正确的具体对象时,使用“WhereTargetHas”方法:

    Bind<IInterface>().To<YourConcreteTypeOne>().WhereTargetHas<ObjectOneAttribute>();
    Bind<IInterface>().To<YourConcreteTypeTwo>().WhereTargetHas<ObjectTwoAttribute>();
    

    更新:不使用属性的解决方案:
    使用方法“When”:

    Bind<IInterface>().To<YourConcreteTypeOne>().When(r => r.Target.Name == "concreteObjectOne");  
    Bind<IInterface>().To<YourConcreteTypeTwo>().When(r => r.Target.Name == "concreteObjectTwo")
    

    ;

    【讨论】:

    • 我宁愿不添加属性。文章的最后展示了如何利用约定,例如参数名为 X。这就是我真正想要的。
    • 那太好了。当我在玩弄这个工作时,我已经很接近了,但你是正确的。顺便说一句,我没有任何反对属性的东西,我只是发现在这种情况下它是浪费的。这种类型的配置在我的代码库中并不常见,因此使用 When 方法要好得多。干杯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    相关资源
    最近更新 更多