2010-08-18 130 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