Ninject - 绑定类型列表
Ninject - bind a List of types
我正在使用 Ninject
。我想要做的是映射一个 List
类型,然后将它注入到我的 class:
的构造函数中
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
。
我找不到解决这个简单任务的方法。
变化:
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>
时执行,而不是在此之前执行。
当 Ninject 尝试在 bindDecoyDispatchFilters
方法中解析 IList<IDispatchFilter>>
时,它会查找 IDispatchFilter
在 之前注册的所有绑定 并找到 none。因此 ctor 参数被解析为一个空集合。
不幸的是,您在构造函数中没有收到任何项目的原因是 Ninject 的 Multi Injection works。 Ninject 对 IList<T>
的解析似乎非直观地寻找所有(独立)注册的 <T>
并将它们注入到你的 class 中 IList<T>
,而不是实际上使用明确注册的方法来解析 IList<T>
.
因此,bindDecoyDispatchFilters
(受 .ToMethod(bindDecoyDispatchFilters)
约束)将永远不会被调用,因为 Ninject 将根据注册的类型解析 IList<T>
T
。 (这很容易测试 - 在方法中放置一个断点或 Assert.Fail()
- 它从未被调用过)。
所以如果
Bind<IDispatchFilter>().To<WindowsXpFilter>();
是IList
中唯一需要解决的IDispatchFilter
,那么你可以放弃注册,按照@Fabjan的,直接注册Bind<IDispatchFilter>().To<WindowsXpFilter>();
。多重注入会将其解析为传递给构造函数的 IList<T>
中的单个元素。
然后您可以完全删除 IList<T>
绑定:
Bind<IList<IDispatchFilter>>() ... remove
.ToMethod(bindDecoyDispatchFilters)
.InSingletonScope();
并完全放弃 bindDecoyDispatchFilters
方法。
但是,如果过滤器列表在引导后发生变化,并且您确实需要一个动态工厂方法来 return 向您的构造函数提供可用的过滤器,那么您可以求助于 。
或者,如果您没有很多 class 依赖于 IList<>
,您也可以显式注册每个 class,这再次优先于多重注入,所以引导代码变成:
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();
}
我用来测试的 classes 是:
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());
我正在使用 Ninject
。我想要做的是映射一个 List
类型,然后将它注入到我的 class:
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
。
我找不到解决这个简单任务的方法。
变化:
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>
时执行,而不是在此之前执行。
当 Ninject 尝试在 bindDecoyDispatchFilters
方法中解析 IList<IDispatchFilter>>
时,它会查找 IDispatchFilter
在 之前注册的所有绑定 并找到 none。因此 ctor 参数被解析为一个空集合。
不幸的是,您在构造函数中没有收到任何项目的原因是 Ninject 的 Multi Injection works。 Ninject 对 IList<T>
的解析似乎非直观地寻找所有(独立)注册的 <T>
并将它们注入到你的 class 中 IList<T>
,而不是实际上使用明确注册的方法来解析 IList<T>
.
因此,bindDecoyDispatchFilters
(受 .ToMethod(bindDecoyDispatchFilters)
约束)将永远不会被调用,因为 Ninject 将根据注册的类型解析 IList<T>
T
。 (这很容易测试 - 在方法中放置一个断点或 Assert.Fail()
- 它从未被调用过)。
所以如果
Bind<IDispatchFilter>().To<WindowsXpFilter>();
是IList
中唯一需要解决的IDispatchFilter
,那么你可以放弃注册,按照@Fabjan的,直接注册Bind<IDispatchFilter>().To<WindowsXpFilter>();
。多重注入会将其解析为传递给构造函数的 IList<T>
中的单个元素。
然后您可以完全删除 IList<T>
绑定:
Bind<IList<IDispatchFilter>>() ... remove
.ToMethod(bindDecoyDispatchFilters)
.InSingletonScope();
并完全放弃 bindDecoyDispatchFilters
方法。
但是,如果过滤器列表在引导后发生变化,并且您确实需要一个动态工厂方法来 return 向您的构造函数提供可用的过滤器,那么您可以求助于
或者,如果您没有很多 class 依赖于 IList<>
,您也可以显式注册每个 class,这再次优先于多重注入,所以引导代码变成:
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();
}
我用来测试的 classes 是:
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());