compact-framework - 当具体类型派生自抽象基类时,Ninject 无法解析接口(interface)类型

标签 compact-framework inversion-of-control ioc-container abstract-class ninject

我有一个问题,Ninject 试图解析一个接口(interface)类型,其中具体类型派生自实现接口(interface)的抽象基类。

编辑:这是在使用 .NET CF 的 Windows Mobile 上。

我的特殊问题涉及演示者和 View ,因此在此示例中我坚持使用它而不是 foos 和 bar。

我想为演示者和 View 注入(inject)工厂,以允许在 UI View 堆栈深处创建这些实例。

下面我省略了所有错误检查以提高可读性。

我的工厂界面:

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 在尝试解决依赖关系时抛出。

上面我们看到presenter依赖于view,所以presenter factory会依赖于view factory:
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>>();

到目前为止,一切都完美无缺。演示者工厂中对 View 工厂的依赖已按预期解决。

现在,我有一百万个看起来像上面的 GoodPresenterFactory 的类,因此我想要一个小的基类来处理一些琐碎的常见事情,比如在演示者工厂中对 View 工厂的依赖:
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 相同,除了直接IFactory<Presenter> GoodPresenterFactory 中的实现,而不是 PointlessPresenterFactory 中使用的完全裸基类.

知道为什么在使用工厂基类时 Ninject 无法解决吗?

最佳答案

此问题已在构建 2.3.0.46 中修复,并将成为下一个版本 (2.4) 的一部分。

注意:因为 CF 似乎不允许检测方法是通用的还是不能在基本方法上定义 Inject 属性。它必须在重载方法上定义。

关于compact-framework - 当具体类型派生自抽象基类时,Ninject 无法解析接口(interface)类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5260191/

相关文章:

c# - 使用 Unity 填充集合的方法

c# - 使用ctor注入(inject)和ServiceProvider创建实例

c# - 将实例映射到 Ninject 绑定(bind)中的对象

c# - 紧凑的框架语音识别 API 或库

c# - 将 BMP 转换为 PCX C# Compact Framework

c# - 一次只检查一个 ListViewItem

c# - 如何在 .NET 紧凑型框架中获取默认系统字体?

python - 设计模式名称 : get class from class level

c# - 使用 IoC 容器时如何传入对象

c# - Lucene.Net IndexReader 的 StructureMap 'conditional singleton'