1

我正在尝试使用 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(...

[为什么?]

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

4

3 回答 3

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>();
 }
于 2013-03-04T13:29:39.527 回答
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();
    }
}
于 2013-03-05T08:37:30.723 回答
0

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

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

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

于 2013-03-04T13:21:41.820 回答