ConstructorArgument.Inject打破了Kernel.Get的工作原理

时间:2014-09-26 00:10:39

标签: c# ninject

鉴于以下类别:

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

1 个答案:

答案 0 :(得分:1)

ninject不支持此功能。 ctx.Inject<>中指定的类型必须与构造函数参数的类型完全匹配。 Ninject实际上从不执行new Bar(...),它只分析表达式以确定使用哪个构造函数以及如何注入值。

有两种方法可以调整代码以使其正常工作:

  • 更改Bar的构造函数以接收Foo的{​​{1}}个内容。
  • 更改IFoo的{​​{1}}绑定,使ToConstructorBarctx.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>以及这些东西是如何运作的,最终你会发现它为什么会这样做;-) (我不会为你而去)