Ninject - 绑定类型列表

时间:2018-06-11 15:09:42

标签: c# ninject

我正在使用Ninject。我想要做的是映射List类型,然后将其注入我的类的构造函数中:

private readonly IList<IDispatchFilter> m_Filters;

public DispatchFilteringManager(IList<IDispatchFilter> filters)
{
    m_Filters = filters;
}

我试过这个绑定:

Bind<IList<IDispatchFilter>>()
    .ToMethod(bindDecoyDispatchFilters)
    .InSingletonScope();

private IList<IDispatchFilter> bindDecoyDispatchFilters(IContext context)
{
    Bind<IDispatchFilter>().To<WindowsXpFilter>();

    IList<IDispatchFilter> result = context.Kernel.GetAll<IDispatchFilter>().ToList();

    return result;
}

但是在我的构造函数中,我得到一个空的List

我无法为这项简单的任务找到解决方案。

2 个答案:

答案 0 :(得分:1)

变化:

Bind<IList<IDispatchFilter>>()
    .ToMethod(bindDecoyDispatchFilters)
    .InSingletonScope();

private IList<IDispatchFilter> bindDecoyDispatchFilters(IContext context)
{
    Bind<IDispatchFilter>().To<WindowsXpFilter>();
    ...
}

要:

Bind<IDispatchFilter>().To<WindowsXpFilter>();
Bind<IList<IDispatchFilter>>()
    .ToMethod(bindDecoyDispatchFilters)
    .InSingletonScope();

private IList<IDispatchFilter> bindDecoyDispatchFilters(IContext context)
{
    ...
}

说明:

我们在.ToMethod绑定中使用的方法只会在我们调用T而不是之前调用container.Get<T>时执行IList<IDispatchFilter>>

当Ninject尝试在bindDecoyDispatchFilters方法中解析IDispatchFilter时,它会在之前查找<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> 已注册的所有绑定,但找不到。因此,ctor参数被解析为空集合。

答案 1 :(得分:1)

不幸的是,由于Ninject的Multi Injection works方式,你在构造函数中没有收到任何项目的原因。 Ninject的IList<T>分辨率似乎非直观地查找所有(独立)注册的<T>,并将它们注入到您的班级中IList<T>,而不是实际使用明确注册的方法来解析IList<T> 1}}。

因此,永远不会调用bindDecoyDispatchFilters(由.ToMethod(bindDecoyDispatchFilters)绑定),因为Ninject将根据已注册的类型IList<T>解析T。 (这很容易测试 - 在方法中放置一个断点或Assert.Fail() - 它从未被调用过。)

所以,如果

Bind<IDispatchFilter>().To<WindowsXpFilter>();

是唯一需要在IDispatchFilter中解析的IList,然后您可以删除注册,并按照@ Fabjan的说明直接注册Bind<IDispatchFilter>().To<WindowsXpFilter>();。多注入将解析为传递给构造函数的IList<T>中的单个元素。

然后,您可以完全删除IList<T>绑定:

Bind<IList<IDispatchFilter>>() ... remove 
    .ToMethod(bindDecoyDispatchFilters)
    .InSingletonScope();

并完全放弃bindDecoyDispatchFilters方法。

但是,如果过滤器列表在引导后发生更改,并且您确实需要动态工厂方法将可用的过滤器返回给构造函数,那么您可以使用hack like this

或者,如果您没有很多依赖于IList<>的类,您也可以显式注册每个类,这也优先于多次注入,因此Bootstrapping代码变为:

kernel.Bind<ResolveMe>()
     .ToSelf()
     .WithConstructorArgument<IEnumerable<IDispatchFilter>>(bindDecoyDispatchFilters);

private IList<IDispatchFilter> bindDecoyDispatchFilters(IContext context)
{
    // Contract.Assert(1 == 0); // .. .ensure the method is called during resolution!
    context.Kernel.Bind<IDispatchFilter>().To<WindowsXpFilter>();
    return context.Kernel.GetAll<IDispatchFilter>().ToList();
}

我以前测试的课程是:

public interface IDispatchFilter {}

public class WindowsXpFilter : IDispatchFilter { }

public class ResolveMe
{
    public IEnumerable<IDispatchFilter> Stuff { get; set; }

    public ResolveMe(IEnumerable<IDispatchFilter> stuff) { Stuff = stuff; }
}

还有一些测试:

  var y = kernel.Get<ResolveMe>();
  Assert.IsTrue(y.Stuff.Any());