Der Titel sagt "Circular Dependency", aber es ist nicht der richtige Wortlaut, weil mir das Design solide erscheint.
Stellen Sie sich jedoch das folgende Szenario vor, in dem die blauen Teile von einem externen Partner stammen und Orange meine eigene Implementierung ist. Nehmen wir auch an, es gibt mehr als einen ConcreteMain
, aber ich möchte einen bestimmten verwenden. (In Wirklichkeit hat jede Klasse einige Abhängigkeiten mehr, aber ich habe versucht, es hier zu vereinfachen)
Ich möchte all dies mit Depency Injection (Unity) StackOverflowException
instanziieren , aber ich erhalte offensichtlich einen Hinweis auf den folgenden Code, da Runner versucht, ConcreteMain zu instanziieren, und ConcreteMain einen Runner benötigt.
IUnityContainer ioc = new UnityContainer();
ioc.RegisterType<IMain, ConcreteMain>()
.RegisterType<IMainCallback, Runner>();
var runner = ioc.Resolve<Runner>();
Wie kann ich das vermeiden? Gibt es eine Möglichkeit, dies so zu strukturieren, dass ich es mit DI verwenden kann? Das Szenario, das ich jetzt mache, besteht darin, alles manuell einzurichten, aber das setzt eine harte Abhängigkeit von ConcreteMain
der Klasse voraus, die es instanziiert. Dies ist, was ich zu vermeiden versuche (mit Unity-Registrierungen in der Konfiguration).
Der gesamte Quellcode unten (sehr vereinfachtes Beispiel!);
public class Program
{
public static void Main(string[] args)
{
IUnityContainer ioc = new UnityContainer();
ioc.RegisterType<IMain, ConcreteMain>()
.RegisterType<IMainCallback, Runner>();
var runner = ioc.Resolve<Runner>();
Console.WriteLine("invoking runner...");
runner.DoSomethingAwesome();
Console.ReadLine();
}
}
public class Runner : IMainCallback
{
private readonly IMain mainServer;
public Runner(IMain mainServer)
{
this.mainServer = mainServer;
}
public void DoSomethingAwesome()
{
Console.WriteLine("trying to do something awesome");
mainServer.DoSomething();
}
public void SomethingIsDone(object something)
{
Console.WriteLine("hey look, something is finally done.");
}
}
public interface IMain
{
void DoSomething();
}
public interface IMainCallback
{
void SomethingIsDone(object something);
}
public abstract class AbstractMain : IMain
{
protected readonly IMainCallback callback;
protected AbstractMain(IMainCallback callback)
{
this.callback = callback;
}
public abstract void DoSomething();
}
public class ConcreteMain : AbstractMain
{
public ConcreteMain(IMainCallback callback) : base(callback){}
public override void DoSomething()
{
Console.WriteLine("starting to do something...");
var task = Task.Factory.StartNew(() =>{ Thread.Sleep(5000);/*very long running task*/ });
task.ContinueWith(t => callback.SomethingIsDone(true));
}
}