[英]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
的構造函數以接收IFoo
的Foo
intead。 Bar
的ToConstructor
綁定更改為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
但是,如果你指的是文檔中有關該類型T
在Inject<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.