2010-08-18 123 views
9

我想弄清楚如何用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接口的一个实例的绑定?

感谢您的回答。

回答

15

正如错误消息所述,由于您无法在没有其他实例的情况下创建一个实例,因此您在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; 
    } 
} 
+0

感谢在t他的小费。我发现了财产注入的完美解决方案。但它没有IOtherService OtherService {set; }在IMainServices上,因为当我用[Inject]装饰属性时,Ninject自己添加正确的实例。 – 2010-08-18 13:57:01

+4

这不起作用。使用Ninject的最新版本时,如果您对两者都使用属性注入,它将抛出一个'StackOverflowException',并且如果只有一个使用属性注入(和另一个构造函数注入),将抛出“检测到周期性依赖关系”。 – 2012-08-15 14:23:04

+4

啊,但只要您使用的是非暂时性作用域(默认)的作用域,它*就会工作。 – 2012-08-16 00:57:16

2

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

你建设单位应当是这样的:

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

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

可以使用Load方法你介绍这些懒惰依赖Ninject模块调用,基于GET方法创建懒法“ToMethod(”拉姆达方法“)。

上lazyness如何解决Ninject循环依赖一个明显的例子在这里呈现,还介绍了一个辅助方法(BindLazy)为您解决问题。 https://www.codeproject.com/Tips/1171940/How-Ninject-Can-Help-in-Resolving-Circular-Depende

+0

我用过这个。这非常整齐! – 2017-09-28 10:54:47