簡體   English   中英

ConstructorArgument.Inject在Kernel.Get工作的地方中斷

[英]ConstructorArgument.Inject breaks where Kernel.Get works

給定以下類別:

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

ninject不支持此功能。 ctx.Inject<>指定的類型必須與構造函數參數的類型完全匹配。 Ninject從未實際執行您的new Bar(...) ,它僅分析表達式以確定要使用的構造函數以及如何注入值。

有兩種方法可以修改您的代碼以使其起作用:

  • 更改Bar的構造函數以接收IFooFoo intead。
  • BarToConstructor綁定更改為ToConstructor 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

但是,如果你指的是文檔中有關該類型TInject<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以及這些東西的工作方式,最后您將了解為什么它會像它一樣起作用;-)(我不會為您介紹)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM