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

时间:2013-03-04 12:32:38

标签: c# dependency-injection ninject stack-overflow

我正在尝试使用NInject解析已知的固定Foo服务列表(在单例范围内);这个解决方案发生在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(...

[为什么?]

一般的想法是避免服务定位器模式,因为我已经看到它被描述为反模式。因此,而不是尝试在运行时通过依赖注入器解析服务;您尝试在安装过程中获取服务列表。但问题是,如果您的任何服务想要查找其他服务,则会出现上述问题。

3 个答案:

答案 0 :(得分:1)

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

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>();
 }

答案 1 :(得分:1)

您无法使用Ninject解决此循环依赖关系。您甚至无法手动创建此类对象图。

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

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

如果要避免服务定位器模式,则应从IKernel的构造函数中删除对FooProvider的依赖,并使用注入的IFoo实现集合的注入。

public class FooProvider : IFooProvider
{
    private List<IFoo> _allFooServices;

    public FooProvider(IEnumerable<IFoo> fooServices)
    {
        _allFooServices = fooServices.ToList();
    }
}

答案 2 :(得分:0)

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

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

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