如何使用 Ninject 支持动态多重注入,其中可能没有项目绑定
How to support dynamic multiinjection with Ninject, where there may be NO items bound
在以下单元测试中,TestDirectRetrieval_WithNoImplementations
和 TestInjection_WithNoImplementations
失败
[TestFixture]
public class KernelTests
{
[Test] //Passes
public void TestDirectRetrieval_WithMultipleImplementations()
{
//Arrange
var kernel = new StandardKernel();
kernel.Bind<Foo>().ToConstant(new Foo("a"));
kernel.Bind<Foo>().ToConstant(new Foo("b"));
//Act + Assert
Assert.DoesNotThrow(() => kernel.GetAll<Foo>().ToList());
}
[Test] //Passes
public void TestInjection_WithMultipleImplementations()
{
//Arrange
var kernel = new StandardKernel();
kernel.Bind<Foo>().ToConstant(new Foo("a"));
kernel.Bind<Foo>().ToConstant(new Foo("b"));
//Act + Assert
Assert.DoesNotThrow(() => kernel.Get<Bar>());
}
[Test] //Fails
public void TestDirectRetrieval_WithNoImplementations()
{
//Arrange
var kernel = new StandardKernel();
//Act + Assert
Assert.DoesNotThrow(() => kernel.GetAll<Foo>().ToList());
}
[Test] //Fails
public void TestInjection_WithNoImplementations()
{
//Arrange
var kernel = new StandardKernel();
//Act + Assert
Assert.DoesNotThrow(() => kernel.Get<Bar>());
}
#region Test helper classes
class Foo
{
public Foo(string someArgThatCantBeAutomaticallyResolvedByNinject){}
}
class Bar
{
private List<Foo> myFoos;
public Bar(IEnumerable<Foo> foos)
{
myFoos = foos.ToList();
}
}
#endregion
}
如果有人根据某些动态情况将事物绑定到常量/实现,他们如何支持这种情况,而根本没有任何绑定?
GetAll
未被 ninject 用于注入,但正如您发现的那样,它提供了所需的行为。为了使用 0-n 语义启用注入,我通常会推出自己的 "collection",一个不完整/伪代码版本如下所示:
class OptionalItems<T> : IEnumerable<T>
{
private readonly T[] items;
public OptionalItems(IResolutionRoot resolutionRoot)
{
this.items = resolutionRoot.TryGetAll(T).ToArray();
}
public IEnumerator<T> GetEnumerator() {
return this.items.GetEnumerator();
}
}
现在注入 OptionalItems
而不是 IEnumerable<T>
或 IList<T>
。
出于可测试性的原因,为 OptionalItems
创建一个接口可能是有意义的:public interface IOperationalItems<T> : IEnumerable<T>
并绑定它。
在以下单元测试中,TestDirectRetrieval_WithNoImplementations
和 TestInjection_WithNoImplementations
失败
[TestFixture]
public class KernelTests
{
[Test] //Passes
public void TestDirectRetrieval_WithMultipleImplementations()
{
//Arrange
var kernel = new StandardKernel();
kernel.Bind<Foo>().ToConstant(new Foo("a"));
kernel.Bind<Foo>().ToConstant(new Foo("b"));
//Act + Assert
Assert.DoesNotThrow(() => kernel.GetAll<Foo>().ToList());
}
[Test] //Passes
public void TestInjection_WithMultipleImplementations()
{
//Arrange
var kernel = new StandardKernel();
kernel.Bind<Foo>().ToConstant(new Foo("a"));
kernel.Bind<Foo>().ToConstant(new Foo("b"));
//Act + Assert
Assert.DoesNotThrow(() => kernel.Get<Bar>());
}
[Test] //Fails
public void TestDirectRetrieval_WithNoImplementations()
{
//Arrange
var kernel = new StandardKernel();
//Act + Assert
Assert.DoesNotThrow(() => kernel.GetAll<Foo>().ToList());
}
[Test] //Fails
public void TestInjection_WithNoImplementations()
{
//Arrange
var kernel = new StandardKernel();
//Act + Assert
Assert.DoesNotThrow(() => kernel.Get<Bar>());
}
#region Test helper classes
class Foo
{
public Foo(string someArgThatCantBeAutomaticallyResolvedByNinject){}
}
class Bar
{
private List<Foo> myFoos;
public Bar(IEnumerable<Foo> foos)
{
myFoos = foos.ToList();
}
}
#endregion
}
如果有人根据某些动态情况将事物绑定到常量/实现,他们如何支持这种情况,而根本没有任何绑定?
GetAll
未被 ninject 用于注入,但正如您发现的那样,它提供了所需的行为。为了使用 0-n 语义启用注入,我通常会推出自己的 "collection",一个不完整/伪代码版本如下所示:
class OptionalItems<T> : IEnumerable<T>
{
private readonly T[] items;
public OptionalItems(IResolutionRoot resolutionRoot)
{
this.items = resolutionRoot.TryGetAll(T).ToArray();
}
public IEnumerator<T> GetEnumerator() {
return this.items.GetEnumerator();
}
}
现在注入 OptionalItems
而不是 IEnumerable<T>
或 IList<T>
。
出于可测试性的原因,为 OptionalItems
创建一个接口可能是有意义的:public interface IOperationalItems<T> : IEnumerable<T>
并绑定它。