2010-08-18 6 views
9

Ich versuche herauszufinden, wie man so etwas mit ninject binden.Zyklische Abhängigkeit mit 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>(); 
    } 
} 

Es gibt mir Ausnahme:

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. 

Ich weiß nicht, wie Basismodul zu schreiben. Ich brauche nur eine Instanz von MainClass und eine Instanz von OtherClass (wie Singletons).

Ich habe versucht, die Dinge so:

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

Aber mit dem gleichen Fehler.

Und wie schreibt Bindung für die Verwendung nur einer Instanz für MainClass und IMainService-Schnittstellen?

Danke für die Antworten.

Antwort

15

Wie die Fehlermeldung besagt, haben Sie eine zyklische Abhängigkeit zwischen MainClass und OtherClass, da Sie keine ohne eine Instanz des anderen erstellen können. Im Idealfall sollten Sie Ihre Klassenhierarchie neu strukturieren, um diese Anforderung zu entfernen.

Wenn dies nicht möglich ist, besteht die Lösung darin, die Eigenschafteninjektion für eine (oder beide) Klassen zu verwenden, z.

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

Vielen Dank für t sein Tipp. Ich fand die perfekte Lösung mit der Eigenschaft Injektion. Aber es ist ohne IOtherService OtherService {set; } auf IMainServices, wenn ich mit [Inject] eine Eigenschaft dekoriere, fügt Ninject selbst die richtige Instanz hinzu. –

+4

Dies funktioniert nicht. Mit der neuesten Version von Ninject wird eine 'StackOverflowException' ausgelöst, wenn Sie die Eigenschaft injection für beide verwenden und die" zyklische Abhängigkeit wurde erkannt "ausgelöst, wenn nur eine die Eigenschaft injection (und die andere Konstruktorinjektion) verwendet. –

+4

Ah, aber es funktioniert, solange Sie einen anderen Bereich als den vorübergehenden Bereich verwenden (Standard). –

2

Ich denke, dass Sie keine Eigenschaften oder Setter-Methoden für diese verwenden sollten, verwenden Sie besser Lazyness. Das Konzept der Faulheit löst das Problem. Das Problem ist, dass wenn Sie zirkuläre Abhängigkeit zwischen Objekten haben, unklar wird, was Sie zuerst erstellen. Faulheit löst auf: Sobald ein Objekt wirklich verwendet wird (im Allgemeinen ist dies der Fall, wenn eine öffentliche Methode aufgerufen wird, muss sie existieren). Bitte vermeide Eigenschaften oder Setter, wenn du kannst. Sie machen Ihr Objekt veränderbar (schlecht für Thread-Sicherheit und unnötig, wenn die Abhängigkeit nur einmal injiziert werden soll).

Sie Bauer soll wie folgt aussehen:

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

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

Sie können diese faulen Abhängigkeiten in Sie Ninject Modul mit der Load-Methode durch den Aufruf „ToMethod (“ Lambda-Verfahren beschreiben, die auf der Grundlage der Methode get die Faulen Methode erstellt „).

ein klares Beispiel dafür, wie lazyness zirkuläre Abhängigkeiten mit Ninject lösen kann, wird hier vorgestellt. Es beschreibt auch eine Hilfsmethode (BindLazy) Ihr Problem zu lösen. https://www.codeproject.com/Tips/1171940/How-Ninject-Can-Help-in-Resolving-Circular-Depende

+0

Ich habe das benutzt. Das war ziemlich ordentlich! –

Verwandte Themen