解决客户端与服务器之间的循环依赖性

时间:2019-08-01 08:42:39

标签: c# wpf dependency-injection unity-container circular-dependency

我有一个用C#编写的客户端和服务器类。两者都需要相互通信(将来有几个客户端将与服务器通信)。但是我遇到了循环依赖。因为我使用unity进行依赖注入,所以我的程序冻结并崩溃了。

我试图使用客户端和服务器之间的接口作为消息提供者。但无论如何还是会崩溃,因为该接口的实现引用了客户端和服务器,并且引用了该接口。

该项目确实很大,但我尝试将其削减:

   public class Client
{
    private Server server;

    public Client(Server server)
    {
        this.server=server;
    }

    public SendToServer(string message)
    {
        server.Receive(message);
    }

    public Receive(string message)
    {

    }
}

public class Server
{
    private Client client;

    public Server(Client client)
    {
        this.client=client;
    }

    public SendToClient(string message)
    {
        client.Receive(message);
    }

    public Receive(string message)
    {

    }
}

所有这些都在WPF中的UserControl内部运行。客户端被注入到视图的构造函数中。然后,Unity将Server注入到Client构造函数中,这将触发Server构造函数,而Server构造函数将再次触发Client构造函数。

public partial class ClientView: UserControl
{
    public ClientView(Client client)
    {
        this.DataContext = client;
        InitializeComponent();
    }

}

1 个答案:

答案 0 :(得分:3)

乍一看,这似乎很可疑,但是如果您使用的是这种组合,则需要以某种方式打破依赖性循环。

一种方法是创建依赖关系的抽象,并对一个不依赖于另一个的实现进行多种实现。例如

public interface IServer { void Receive(string message); void SendToClient(string message); }
public interface IClient { void Receive(string message); void SendToServer(string message); }

public class Client : IClient
{
    // This will be set as SimpleServer-implementation
    private readonly IServer _server;

    public Client(IServer server) => _server = server;

    public void SendToServer(string message) => _server.Receive(message);

    public void Receive(string message) => Console.WriteLine($"Client received: {message}");
}

public class Server : IServer
{
    private readonly IClient _client;

    public Server(IClient client) => _client = client;

    public void SendToClient(string message) => _client.Receive(message);

    public void Receive(string message) => Console.WriteLine($"Server received: {message}");
}

public class SimpleServer : IServer
{
    public void SendToClient(string message) { }

    public void Receive(string message) => Console.WriteLine($"SimpleServer received: {message}");
}

void Main()
{
    var container = new UnityContainer();
    container.RegisterType<IServer, Server>();
    container.RegisterType<IClient, Client>(new InjectionConstructor(container.Resolve<SimpleServer>()));

    var server = container.Resolve<IServer>();
    var client = container.Resolve<IClient>();

    server.SendToClient("Foo");
    client.SendToServer("Bar");
}

处理此问题的另一种方法是在工厂的帮助下延迟初始化一个依赖项。这样,我们可以在第一次使用依赖项时延迟加载它。在下面的示例中,我将Func委托用作工厂并将其包装在Lazy中。

public interface IServer { void Receive(string message); void SendToClient(string message); }
public interface IClient { void Receive(string message); void SendToServer(string message); }

public class Client : IClient
{
    private readonly IServer _server;

    public Client(IServer server) => _server = server;

    public void SendToServer(string message) => _server.Receive(message);

    public void Receive(string message) => Console.WriteLine($"Client received: {message}");
}

public class Server : IServer
{
    private readonly Lazy<IClient> _client;

    public Server(Func<IClient> clientFactory) 
        => _client = new Lazy<IClient>(() => clientFactory());

    public void SendToClient(string message) => _client.Value.Receive(message);

    public void Receive(string message) => Console.WriteLine($"Server received: {message}"); }
}

void Main()
{
    var container = new UnityContainer();
    container.RegisterType<IClient, Client>();
    container.RegisterType<IServer, Server>();
    var server = container.Resolve<IServer>();
    var client = container.Resolve<IClient>();
    server.SendToClient("Foo");
    client.SendToServer("Bar");
}