我正在使用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
。
我无法为这项简单的任务找到解决方案。
答案 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());