我正在尝试使用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(...
[为什么?]
一般的想法是避免服务定位器模式,因为我已经看到它被描述为反模式。因此,而不是尝试在运行时通过依赖注入器解析服务;您尝试在安装过程中获取服务列表。但问题是,如果您的任何服务想要查找其他服务,则会出现上述问题。
答案 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。