Tiêu đề nói "Phụ thuộc tròn", nhưng nó không phải là từ ngữ chính xác, bởi vì với tôi thiết kế có vẻ vững chắc.
Tuy nhiên, hãy xem xét kịch bản sau đây, trong đó các phần màu xanh được đưa ra từ đối tác bên ngoài và màu cam là triển khai của riêng tôi. Cũng giả sử có nhiều hơn một ConcreteMain
, nhưng tôi muốn sử dụng một cái cụ thể. (Trong thực tế, mỗi lớp có một số phụ thuộc hơn, nhưng tôi đã cố gắng đơn giản hóa nó ở đây)
Tôi muốn kích hoạt tất cả những điều này với Depency Injection (Unity), nhưng rõ ràng tôi nhận được một StackOverflowException
đoạn mã sau, bởi vì Runner cố gắng khởi tạo ConcreteMain và ConcreteMain cần một Runner.
IUnityContainer ioc = new UnityContainer();
ioc.RegisterType<IMain, ConcreteMain>()
.RegisterType<IMainCallback, Runner>();
var runner = ioc.Resolve<Runner>();
Làm thế nào tôi có thể tránh điều này? Có cách nào để cấu trúc cái này để tôi có thể sử dụng nó với DI không? Kịch bản tôi đang làm bây giờ là thiết lập mọi thứ theo cách thủ công, nhưng điều đó đặt ra một sự phụ thuộc lớn vào ConcreteMain
lớp tạo ra nó. Đây là những gì tôi đang cố gắng tránh (với đăng ký Unity trong cấu hình).
Tất cả các mã nguồn dưới đây (ví dụ rất đơn giản!);
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));
}
}