4

我嘗試解析接口類型,其中具體類型從實現接口的抽象基類派生的Ninject存在問題。當抽象基類派生具體類型時,Ninject無法解析接口類型

編輯:這是在Windows Mobile上使用.NET CF.

我的問題涉及到演示者和視圖,所以我堅持在這個例子中,而不是foos和酒吧。

我想爲演示者和視圖注入工廠,以允許在UI視圖堆棧內深入創建這些實例。

下面我省略了所有錯誤檢查以提高可讀性。

我的工廠接口:

public interface IFactory<T> 
{ 
    T Create(); 
} 

我的演講和觀點:

public sealed class Presenter 
{ 
    private readonly View view; 

    public Presenter(View view) 
    { 
     this.view = view; 
    } 
} 

public sealed class View 
{ 
    public View() 
    { 
    } 
} 

首先,我會告訴什麼完美的作品,那Ninject如預期解析。這將不包括我在開始時提到的抽象基類。在此之後,我將添加對抽象基類的輕微修改,這會在嘗試解決依賴關係時導致Ninject拋出。

我們看到上面演示依賴於視圖,因此主持人工廠將取決於視圖工廠:

public sealed class GoodPresenterFactory : IFactory<Presenter> 
{ 
    private readonly IFactory<View> viewFactory; 

    public GoodPresenterFactory(IFactory<View> viewFactory) 
    { 
     this.viewFactory = viewFactory; 
    } 

    public Presenter Create() 
    { 
     return new Presenter(this.viewFactory.Create()); 
    } 
} 

public sealed class ViewFactory : IFactory<View> 
{ 
    public ViewFactory() 
    { 
    } 

    public View Create() 
    { 
     return new View(); 
    } 
} 

接線這個了Ninject:

Bind<IFactory<Presenter>>().To<GoodPresenterFactory>(); 
Bind<IFactory<View>>().To<ViewFactory>(); 

然後解析主持人工廠:

var presenterFactory = container.Get<IFactory<Presenter>>(); 

到目前爲止,一切都很完美。按預期方式解決演示者工廠內對視圖工廠的依賴關係。

現在,我有一百萬的類,看起來像GoodPresenterFactory上方,所以我想要一個小的基類來處理一些瑣碎的共同的東西,就像在演示工廠視圖工廠的依賴:

public abstract class FactoryBase<T, U> : IFactory<T> 
{ 
    protected readonly U dependency; 

    protected FactoryBase(U dependency) 
    { 
     this.dependency = dependency; 
    } 

    public abstract T Create(); 
} 

然後主持人工廠將有所改變,一些在變化將使Ninject無法解析:

public sealed class BadPresenterFactory : FactoryBase<Presenter, IFactory<View>> 
{ 
    public BadPresenterFactory(IFactory<View> viewFactory) 
     : base(viewFactory) 
    { 
    } 

    public override Presenter Create() 
    { 
     return new Presenter(this.dependency.Create()); 
    } 
} 

並據此改變Ninject接線:

Bind<IFactory<Presenter>>().To<BadPresenterFactory>(); 
Bind<IFactory<View>>().To<ViewFactory>(); 

這些變化將會使Ninject拋出一個ArgumentNullException從異常做

var presenterFactory = container.Get<IFactory<Presenter>>(); 

調用堆棧時:

at System.Reflection.RuntimeMethodInfo.GetParentDefinition() 
at System.Reflection.CustomAttribute.IsDefined(MemberInfo member, Type caType, Boolean inherit) 
at System.Reflection.RuntimeMethodInfo.IsDefined(Type attributeType, Boolean inherit) 
at System.Attribute.IsDefined(MemberInfo element, Type attributeType, Boolean inherit) 
at System.Attribute.IsDefined(MemberInfo element, Type attributeType) 
at Ninject.Infrastructure.Language.ExtensionsForMemberInfo.HasAttribute(MemberInfo member, Type type) 
at Ninject.Selection.Heuristics.StandardInjectionHeuristic.ShouldInject(MemberInfo member) 
at Ninject.Selection.Selector.<>c__DisplayClassa.<SelectMethodsForInjection>b__9(IInjectionHeuristic h) 
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate) 
at Ninject.Selection.Selector.<SelectMethodsForInjection>b__8(MethodInfo m) 
at System.Linq.Enumerable.<WhereIterator>d__0`1.MoveNext() 
at Ninject.Planning.Strategies.MethodReflectionStrategy.Execute(IPlan plan) 
at Ninject.Planning.Planner.<>c__DisplayClass2.<GetPlan>b__0(IPlanningStrategy s) 
at Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map[T](IEnumerable`1 series, Action`1 action) 
at Ninject.Planning.Planner.GetPlan(Type type) 
at Ninject.Activation.Providers.StandardProvider.Create(IContext context) 
at Ninject.Activation.Context.Resolve() 
at Ninject.KernelBase.<Resolve>b__4(IContext context) 
at System.Linq.Enumerable.<SelectIterator>d__d`2.MoveNext() 
at System.Linq.Enumerable.<CastIterator>d__b0`1.MoveNext() 
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source) 
at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters) 
at NinjectTest.Program.Main() 

如果我修改FactoryBase所以它沒有依賴關係,它只是一個裸基類,那麼Ninject也失敗。

public abstract class NakedFactoryBase<T> : IFactory<T> 
{ 
    protected NakedFactoryBase() 
    { 
    } 

    public abstract T Create(); 
} 

public sealed class PointlessPresenterFactory : NakedFactoryBase<Presenter> 
{ 
    private readonly IFactory<View> viewFactory; 

    public PointlessPresenterFactory(IFactory<View> viewFactory) 
    { 
     this.viewFactory = viewFactory; 
    } 

    public override Presenter Create() 
    { 
     return new Presenter(this.viewFactory.Create()); 
    } 
} 

正如你可以看到,故障PointlessPresenterFactory是相同的後續GoodPresenterFactory,除了在GoodPresenterFactory直接IFactory<Presenter>執行,而不是在PointlessPresenterFactory使用的completeley裸基類。

任何想法爲什麼Ninject在使用工廠基類時無法解決?

+0

我不知道爲什麼會發生這種情況,但這是一個非常好的問題,寫得很好,有很好的文檔。我很想看到答案。由於@Nate Kohari在Stack Overflow上,我想你會得到答案。 – 2011-03-10 13:34:04

+0

我完全複製了您的所有代碼,但無法獲取該錯誤。你使用的是什麼版本的ninject? (我正在使用2.2.0.1) – ryber 2011-03-10 16:33:02

+0

@John Bledsloe:@Nate Kohari並不完全是自殺,雖然他是:P @Remo Gloor將會毫無疑問! – 2011-03-10 16:49:42

回答

3

此問題已在Build 2.3.0.46中修復,並將成爲下一版本(2.4)的一部分。

注意:由於CF似乎不允許檢測到方法是通用的,因此無法在基本方法上定義Inject屬性。它必須在過載方法中定義。