鉴于以下类别:
interface IFoo { }
class Foo : IFoo { }
class Bar
{
public Bar(IFoo foo) { }
}
和绑定:
Bind<Bar>().ToConstructor(ctx => new Bar(ctx.Inject<Foo>()));
调用kernel.Get<Bar>()
会引发以下异常:
An unhandled exception of type 'Ninject.ActivationException' occurred in Ninject.dll
Additional information: Error activating IFoo
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IFoo into parameter foo of constructor of type Bar
1) Request for Bar
但是,如果我将绑定更改为:
Bind<Bar>().ToMethod(ctx => new Bar(ctx.Kernel.Get<Foo>()));
我可以按预期获得Bar
的实例。
为什么我会得到那个例外?我认为两个绑定几乎完全相同,在这两种情况下都不会激活IFoo
的实例。
(不)工作小提琴可以在这里看到:https://dotnetfiddle.net/qmPFhr
答案 0 :(得分:1)
ninject不支持此功能。 ctx.Inject<>
中指定的类型必须与构造函数参数的类型完全匹配。 Ninject实际上从不执行new Bar(...)
,它只分析表达式以确定使用哪个构造函数以及如何注入值。
有两种方法可以调整代码以使其正常工作:
Bar
的构造函数以接收Foo
的{{1}}个内容。IFoo
的{{1}}绑定,使ToConstructor
与Bar
(ctx.Inject<>()
)的构造函数匹配,并为Bar
创建绑定:
ctx.Inject<IFoo>()
没有记录在源/ api之外的任何其他文档中,IFoo
实际上并未执行。但是,从方法的参数是Bind<IFoo>().To<Foo>();
Bind<Bar>().ToConstructor(ctx => new Bar(ctx.Inject<IFoo>()));
而不是ctx.Inject<>
非常明显。如果它将被执行,Expression<Func<..>>
就足够了。 Func<..>
已经存在,因此您可以分析其内容。
此外,在查看BindingBuilder.cs
的来源时,Func<..>
方法实际上只做了一件事:抛出异常:
Expression
另见:http://ivanitskyi.blogspot.com/2013/06/linq-func-vs-expression.html
但是,如果您引用有关Inject<T1>
public T1 Inject<T1>()
{
throw new InvalidOperationException("This method is for declaration that a parameter shall be injected only! Never call it directly.");
}
类型的文档必须完全匹配:答案是否定的。我找不到任何关于它的文件。但是,作为它的开源,我们可以再次考虑实现。同样,它在BindingBuilder.cs
中找到,其中包含:
T
你可以从那里看看Inject<T>
以及这些东西是如何运作的,最终你会发现它为什么会这样做;-)
(我不会为你而去)