ConstructorArgument.Inject 中断了 Kernel.Get 工作的地方

本文关键字:工作 Get Kernel Inject 中断 ConstructorArgument | 更新日期: 2023-09-27 18:24:27

给定以下类:

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

ConstructorArgument.Inject 中断了 Kernel.Get 工作的地方

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

有两种

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

  • 更改 Bar 的构造函数以接收IFooFoo
  • 更改 BarToConstructor绑定,使其ctx.Inject<>()Bar (ctx.Inject<IFoo>()( 的构造函数匹配,并为IFoo创建绑定:

.

Bind<IFoo>().To<Foo>();
Bind<Bar>().ToConstructor(ctx => new Bar(ctx.Inject<IFoo>()));

根据您的文件要求

不,除了源/api之外,它没有记录在任何其他文档中,ctx.Inject<>实际上从未执行过。但是,从该方法的参数中可以明显看出是Expression<Func<..>>而不是Func<..>。如果执行,Func<..>就足够了。 Expression在那里,因此您可以分析它们的内容。

另外,在查看BindingBuilder.cs源时,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.");
}

另请参阅:http://ivanitskyi.blogspot.com/2013/06/linq-func-vs-expression.html

但是,如果您指的是有关Inject<T> T类型必须完全匹配的文档:答案是否定的。我找不到任何关于它的文档。但是,由于它是开源的,我们可以再次查看实现。同样,它在 BindingBuilder.cs 中找到,其中包含:

protected IBindingWhenInNamedWithOrOnSyntax<TImplementation> InternalToConstructor<TImplementation>(
    Expression<Func<IConstructorArgumentSyntax, TImplementation>> newExpression)
{
    var ctorExpression = newExpression.Body as NewExpression;
    if (ctorExpression == null)
    {
        throw new ArgumentException("The expression must be a constructor call.", "newExpression");
    }
    this.BindingConfiguration.ProviderCallback = StandardProvider.GetCreationCallback(ctorExpression.Type, ctorExpression.Constructor);
    this.BindingConfiguration.Target = BindingTarget.Type;
    this.AddConstructorArguments(ctorExpression, newExpression.Parameters[0]);
    return new BindingConfigurationBuilder<TImplementation>(this.BindingConfiguration, this.ServiceNames, this.Kernel);
}

你可以从那里看看AddConstructorArguments以及这些东西是如何工作的,最终你会发现为什么它的行为如此;-((我不会为你这样做(