使用Ninject解析服务时堆栈溢出

本文关键字:堆栈 栈溢出 服务 Ninject 使用 | 更新日期: 2023-09-27 18:01:59

我试图解决一个已知的固定列表Foo服务(在单例范围内)使用NInject;这个解析发生在FooProvider的构造函数中。问题是每个Foo也需要这个提供程序。

public interface IFoo { }
public interface IFooProvider { }
public class Foo : IFoo
{
    private readonly IFooProvider _provider;
    public Foo(IFooProvider provider)
    {
        _provider = provider;
    }
}
public class FooProvider : IFooProvider
{
    private List<IFoo> _allFooServices;
    public FooProvider(IKernel kernel)
    {
        _allFooServices = kernel.GetAll<IFoo>().ToList();
    }
}
public class Program
{
    private static void Main(string[] args)
    {
        var IoC = new StandardKernel();
        IoC.Bind<IFoo>().To<Foo>().InSingletonScope();
        IoC.Bind<IFooProvider>().To<FooProvider>().InSingletonScope();
        var foo = IoC.Get<IFoo>();
    }
}

这里有一个逻辑循环,很明显,堆栈溢出显示它正在往下走。但是,我将两个接口都绑定到单例。

正在考虑;我们尝试解析IFoo,然后需要解析IFooProvider,它本身需要一个IFoo列表…但是我们还没有解决任何IFoo单例,因为我们还在努力解决它!

那么我该如何解决这个问题呢?

[编辑]可能的解决方案;IFoo服务实例延迟缓冲。

public FooProvider(IKernel kernel)
{
    _kernel = kernel;
}
public IFoo Find(object context)
{
    if (_allFooServices == null)
        _allFooServices = _kernel.GetAll<IFoo>().ToList();
    return _allFooServices.Where(...

(为什么?)

一般的想法是避免使用服务定位器模式,因为我看到它被描述为一种反模式。因此,与其尝试在运行时通过依赖注入器来解析服务;您尝试在安装过程中获取服务列表。但问题是,如果你的任何一个服务想要找到其他服务,你就会遇到上述问题。

使用Ninject解析服务时堆栈溢出

不能用Ninject解决这个循环依赖。你甚至不能手工创建这样的对象图。

首先你必须从至少一个构造函数中移除循环依赖。你可以把这个依赖项移到属性中,并使用属性注入。

public class Foo : IFoo
{
   [Inject]
   public IFooProvider Provider { get; set; }
}

如果你想避免服务定位器模式,你应该从FooProvider的构造函数中移除对IKernel的依赖,而使用注册IFoo实现的集合注入。

public class FooProvider : IFooProvider
{
    private List<IFoo> _allFooServices;
    public FooProvider(IEnumerable<IFoo> fooServices)
    {
        _allFooServices = fooServices.ToList();
    }
}

您可以对其中一个使用属性注入。

public interface IFoo
{
}
public interface IFooProvider
{
}
public class Foo : IFoo
{
   [Inject]
   public IFooProvider Provider { get; set; }
}
public class FooProvider : IFooProvider
{
   private List<IFoo> _allFooServices;
   public FooProvider(IKernel kernel)
   {
      _allFooServices = kernel.GetAll<IFoo>().ToList();
   }
}
private static void Main(string[] args)
{
   var IoC = new StandardKernel();
   IoC.Bind<IFoo>().To<Foo>().InSingletonScope();
   IoC.Bind<IFooProvider>().To<FooProvider>().InSingletonScope();
   var foo = IoC.Get<IFoo>();
 }

这似乎是糟糕的设计,但直接回答你的问题,不要在构造函数中实例化_allFooServices。你可以这样做:

private List<IFoo> _allFooServices;
private List<IFoo> AllFooServices
{
    get { return _allFooServices ?? (_allFooServices = Kernel.GetAll<IFoo>().ToList()) }
}

也许你可以选择一个更具体的例子,而不是Foo.