在 Ninject 中注入接口数组 [英] Inject Array of Interfaces in Ninject

查看:57
本文介绍了在 Ninject 中注入接口数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码.

public interface IFoo { }


public class Bar
{
    public Bar(IFoo[] foos) { }
}


public class MyModule : NinjectModule
{
    public override void Load()
    {
        Bind<IFoo[]>().ToConstant(new IFoo[0]);
        // ToConstant() is just an example
    }
}


public class Program
{
    private static void Main(string[] args)
    {
        var kernel = new StandardKernel(new MyModule());
        var bar = kernel.Get<Bar>();
    }
}

当我尝试运行该程序时,出现以下异常.

When I try to run the program I get the following exception.

激活 IFoo 时出错
没有匹配的绑定可用,并且类型不可自绑定.
激活路径:
2) 将依赖项 IFoo 注入 Bar
类型的构造函数的参数 foos1) 请求酒吧

Error activating IFoo
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IFoo into parameter foos of constructor of type Bar
1) Request for Bar

如何在 Ninject 中注入/绑定到数组?

How can I inject / bind to an array in Ninject?

感谢您的时间.


我的应用程序导入由第三方组件创建的数据.导入过程应用不同类型的过滤器(例如不同过滤器接口的实现).过滤规则经常变化,但过于复杂,无法通过纯配置(和主过滤器)完成.


My application imports data which is created by a third party component. The import process applies different kind of filters (e.g. implementations of different filter interfaces). The rules for filtering change quite often but are too complex to be done with pure configuration (and a master filter).

我想让添加/编辑过滤器尽可能简单.我拥有的是一个程序集,其中所有过滤器实现都位于其中.我尝试将每个过滤器接口绑定到以下方法(它提供了该过滤器类型的每个实现的实例).基本上我想避免在添加/删除过滤器类时更改 Ninject 模块的需要.

I want to make adding/editing filters as easy as possible. What I have is an assembly where all the filter implementations are located in. I tried to bind every filter interface to the following method (which provides an instance of every implementation of that filter type). Basically I want to avoid the need to change my Ninject module when I add/remove filter classes.

    private IEnumerable<TInterface> GetInterfaceImplementations<TInterface>(IContext context)
    {
        return GetType().Assembly.GetTypes()
            .Where(t => typeof (TInterface).IsAssignableFrom(t) && IsConcreteClass(t))
            .Select(t => Kernel.Get(t)).Cast<TInterface>();
    }

我对绕过容器 DI 机制感到有点内疚.这是一种不好的做法吗?做这样的事情有没有普遍的做法?

I am feeling a bit guilty in terms of bypassing the containers DI mechanism. Is this a bad practice? Is there a common practice to do such things?

解决方案:
我使用 bsnote 建议的包装类.

Resolution:
I use a wrapper class as bsnote suggested.

推荐答案

这主要是对@bsnote 的回答(我已经 +1d)的重述,这可能有助于理解为什么它会以这种方式工作.

This is largely a restatement of @bsnote's answer (which I've +1d) which may help in understanding why it works in this manner.

Ninject(和其他 DI/插件框架)有两个不同的功能:

Ninject (and other DI / addin frameworks) have two distinct facilities:

  1. 要么绑定到单个明确的服务实现的概念 (Get)
  2. 一种允许获取一组服务的工具 [然后以编程方式选择其中一个或以某种方式聚合](Ninject 中的 GetAll/ResolveAll)

您的示例代码碰巧使用了与上述 2. 相关联的语法.(例如,在 MEF 中,通常使用 [ImportMany] 注释来说明这一点)

Your example code happens to use syntax that's associated with 2. above. (e.g., in MEF, one typically use [ImportMany] annotations to make this clear)

我需要查看示例(查看源代码 - 它非常简短、干净且易于理解)以找到解决此问题的方法.

I'd need to look in the samples (look at the source - its really short, clean and easy to follow) to find a workaround for this.

但是,正如@bsnote 所说,重构您的需求的一种方法是将数组包装在容器中,或者拥有您要求的对象(即,工厂方法或存储库类型构造)

However, as @bsnote says, one way of refactoring your requirement is to wrap the array either in a container, or to have an object that you ask for it (i.e., a factory method or repository type construct)

解释您的真实情况也可能对您有用 - 为什么有裸数组?肯定有一组项目构造要求在所有这些基础上进行封装 - 这个问题肯定不会出现太多?

It may also be useful for you to explain what your real case is - why is there a naked array ? Surely there is a collection of items construct begging to be encapsulated underlying all this - this question certainly doesnt come up much?

扩展中有一组扫描示例,我认为它们会攻击您正在尝试做的很多事情(在 StructureMap 之类的东西中,这种东西更加集成,显然有优点和缺点).

There are a set of scanning examples in the extensions that I imagine would attack a lot of the stuff you're trying to do (In things like StructureMap, this sort of stuff is more integrated, which obviously has pros and cons).

根据您是否尝试实现约定优于配置,您可能需要考虑在每种类型的插件上粘贴一个标记界面.然后你可以显式地Bind每一个.或者,对于 CoC,您可以使 ModuleLoad() 例程循环遍历您生成的一组实现(即,许多单独的 Getcode>s) 在您的编辑中.

Depending on whether you're trying to achieve convention over configuration or not, you might want to consider sticking a marker interface on each type of plugin. Then you can explicitly Bind each one. Alternately, for CoC, you can make the Module's Load() routine loop over the set of implementations you generate (i.e., lots of individual Gets) in your edit.

无论哪种方式,当您有多个注册到位时,您都可以愉快地请求"一个 T[]IEnumerable 并获得完整的集合.如果您想明确地实现这一点(即服务定位器及其暗示的所有内容 - 就像您正在做的那样,您可以使用 GetAll 对它们进行批处理,这样您就不会进行隐含在你这样做的方式.

Either way, when you have the multiple registrations in place you can happily either 'request' a T[] or IEnumerable<T> and get the full set. If you want to achieve this explicitly (i.e., Service Locator and all it implies - like in you're doing, you can use GetAll to batch them so you're not doing the looping that's implicit in the way you've done it.

不确定您是否建立了这种联系,或者我是否遗漏了什么.无论哪种方式,我都希望它教会了您在超过 1000 字的问题中粘贴一些代码:P

Not sure if you've made this connection or if I'm missing something. Either way, I hope it's taught you to stick some code into questions as it speaks > 1000 words :P

这篇关于在 Ninject 中注入接口数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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