与ninject的循环依赖

时间:2010-08-18 11:29:07

标签: c# dependency-injection inversion-of-control ninject

我正试图弄清楚如何用ninject绑定这样的东西的正确方法。

interface IMainService
{
    void DoStuff();
}

interface IOtherService
{
    void DoSomeMagic();
}

abstract class BaseClass
{
    //many stuff here
}

class MainClass : BaseClass, IMainService
{
    public MainClass(IOtherService s)
    {
    }

    public void DoStuff()
    {
        throw new NotImplementedException();
    }

    //do many other things
}

class OtherClass : IOtherService
{
    public OtherClass(IMainService s)
    {
    }

    public void DoSomeMagic()
    {
        throw new NotImplementedException();
    }
}

class BaseModule : NinjectModule
{
    public override void Load()
    {
        Bind<MainClass>().To<MainClass>();
        Bind<IMainService>().To<MainClass>();
        Bind<IOtherService>().To<OtherClass>();
    }
}

static class Program
{
    static void Main()
    {
        var kernel = new StandardKernel(new BaseModule());
        var main = kernel.Get<MainClass>();
    }
}

它给了我例外:

Error activating IOtherService using binding from IOtherService to OtherClass
A cyclical dependency was detected between the constructors of two services.

Activation path:
  4) Injection of dependency IOtherService into parameter s of constructor of type MainClass
  3) Injection of dependency IMainService into parameter s of constructor of type OtherClass
  2) Injection of dependency IOtherService into parameter s of constructor of type MainClass
  1) Request for MainClass

Suggestions:
  1) Ensure that you have not declared a dependency for IOtherService on any implementations of the service.
  2) Consider combining the services into a single one to remove the cycle.
  3) Use property injection instead of constructor injection, and implement IInitializable if you need initialization logic to be run after property values have been injected.

我不知道如何编写BaseModule。我只需要一个MainClass实例和一个OtherClass实例(如单例)。

我尝试过这样的事情:

Bind<MainClass>().To<MainClass>().InSingletonScope();
Bind<IMainService>().To<MainClass>().InRequestScope();
Bind<IOtherService>().To<OtherClass>().InSingletonScope();

但同样的错误。

如何为MainClass和IMainService接口只使用一个实例编写绑定?

感谢您的回答。

2 个答案:

答案 0 :(得分:16)

正如错误消息所示,您在MainClassOtherClass之间存在循环依赖关系,因为如果没有另一个实例,则无法创建一个依赖关系。理想情况下,您应该重新构建类层次结构以删除此要求。

如果不能,解决方案是对一个(或两个)类使用属性注入,例如

public interface IMainService
{
    void DoStuff();
    IOtherService OtherService { set; }
}

public class MainClass
{
    public IOtherService OtherService { get; set; }
    public void DoStuff() { ... }
}

public class OtherService
{
    public OtherService(IMainService main)
    {
        main.OtherService = this;
    }
}

答案 1 :(得分:4)

我认为你不应该使用属性或setter方法,你最好使用Lazyness。懒惰的概念解决了这个问题。问题是,如果对象之间存在循环依赖关系,则不清楚要创建第一个对象。懒惰解析是:一旦真正使用了对象(通常在调用公共方法时就是这种情况,它需要存在)。如果可能,请避免使用属性或安装者。它们使您的对象变得可变(对于线程安全性不利,并且在依赖项应该只注入一次时不需要)。

你的构造函数应该是这样的:

public OtherService(Lazy<IMainService> main)
{
    this.main = main;
}

public MainClass(Lazy<IOtherService> s)
{
    this.s = s;
}

您可以使用Load方法通过调用&#34; ToMethod(&#34;基于get方法创建Lazy方法的lambda方法&#34;)来描述Ninject模块中的这些延迟依赖项。

这里介绍了一个关于懒惰如何解决与Ninject的循环依赖关系的明显例子。它还描述了一个帮助方法(BindLazy)来解决您的问题。 https://www.codeproject.com/Tips/1171940/How-Ninject-Can-Help-in-Resolving-Circular-Depende