【问题标题】:Should I use dependency injection when two instances must share a single third instance?当两个实例必须共享一个第三个实例时,我应该使用依赖注入吗?
【发布时间】:2016-04-04 19:03:40
【问题描述】:

我有一个应用程序同时用作“客户端”和“服务器”来展示它们之间的单一通信。在这个应用程序中,我有一个名为“ClientConnectionService”的类,它包含客户端通信的所有方法:

public class ClientConnectionService : ConnectionModelBase
{
    public string Connect()
    {
        //Some code here
    }

    public void OnDataReceived()
    {
        //Some code here
    }

    public virtual void WaitForData()
    {
        //Some code here
    }

    public void SendMessage(string msg)
    {
        //Some code here
    }

    public string Disconnect()
    {
        //Some code here
    }
}

使用 MVVM,我为 2 个用户控件创建了一个视图和一个 ViewModel:ConnectToServerView/ViewModel 和 ViewUserView/ViewModel。

public partial class ViewUserView : UserControl
{
    private ViewUserViewModel viewModel = new ViewUserViewModel();

    public ViewUserView()
    {
        DataContext = viewModel;
    }
}


public class ViewUserViewModel : ViewModelBase
{
        private ClientConnectionService clientConnectionService 
        = new ClientConnectionService();

        public ViewUserViewModel()
        {

        }

}

另一个 View/ViewModel 与上面的基本相同,所以我将跳过那个的代码(为简单起见)。

我知道这是错误的,因为当尝试访问 ViewUserViewModel 中“客户端”的套接字时,它显示为空(因为我没有调用“连接”方法,实际上我在其中设置了这个“客户端套接字”) ,因为“ClientConnectService”的这个实例与我在“ConnectToServerViewModel”中调用的实例不同。

TL;DR 我有 2 个 viewModel 和一个类的 2 个不同实例,我需要在这些(可能还有更多)viewModel 之间共享该实例(类的)。

我的问题是:依赖注入是否可行? (因为我一直在尝试实现它,但接口始终为空,所以我认为我遗漏了一些东西),或者有没有办法让这个“ClientConnectionService”类在我的所有 ViewModel 实例之间“共享”(或者至少是需要它们的人)

【问题讨论】:

  • 看起来确实是使用依赖注入的好地方。你当然可以使用单例,但是你会在这里和那里一次又一次地添加它们,然后你最终会想要对事物进行单元测试......
  • 这是一种方法。此外,ViewUserViewModel 是一种巨大的代码气味。不确定你到底在用它做什么,但你不应该用他们自己的视图模型来设计用户控件。这样想——TextBox 有绑定到它的 DataContext 的 TextBoxViewModel 吗? Grid 是否有 GridViewModel?通常,您的 ViewUserView 应该在其表面(例如,用户)上公开您绑定到实际视图模型的属性(例如,可能有一个名为 Users 的集合和一个绑定到此用户属性的属性 SelectedUser)。跨度>
  • @Will,感谢您的输入,但为了简单起见,我只是发布了视图模型的“基本框架”。我可以向你保证,我这样做是有原因的。
  • 那种气味总是让我害怕。闻到就跑!

标签: c# wpf mvvm dependency-injection


【解决方案1】:

依赖注入需要您从容器中解析视图模型。这意味着您需要有某种方法来解析每个视图的视图模型,而不是实例化它们。最好使用一些现成的 MVVM 框架,例如 Caliburn Micro。

您真正需要的是Singleton pattern。尽管 IoC 很不错,但您可能不想仅仅为了在您的应用程序中有一个单例而这样做。

如果你真的想在你的应用程序中使用 IoC 和 DI,你可以查看Caliburn MicroReactiveUI。两者都使用一些简单的服务定位器(检查herehere),用于解析虚拟机和依赖关系。我还为 Autofac 制作了一个sample adaptor,以便与 RxUI 6 一起使用。

【讨论】:

  • DI 并不一定意味着你需要一个容器,DI 只是应用了控制反转原则。是的,容器可以解决这个问题,但也可以只在 main 中实例化一个类的单个实例并将其传递给视图模型,它仍然称为 DI,不是吗?
  • 非常感谢@Alexey Zimarev,这帮助我开发了一个快速解决方案。如果有人想看看我做了什么,请在下面发布答案。
【解决方案2】:

跟进@Alexey Zimarev 的回答,这是我的单例实现版本:

public class ClientConnectionService : ConnectionModelBase
{
    private static readonly ClientConnectionService instance 
    = new ClientConnectionService();

    private ClientConnectionService() { }

    public static ClientConnectionService getClientConnectionService()
    {
        return instance;
    }

    public string Connect(string ipAddress, int portNumber)
    {
        //Some code
    }

    //More code below, just omitted.
}

然后,只需在任何 viewModel 中将其调用为:

public class ConnectToServerViewModel : ViewModelBase
{
    #region Singletons

    private ClientConnectionService clientConnectionService =
    ClientConnectionService.getClientConnectionService();

    #endregion

    //Code omitted for simplicity purposes
}

这解决了我遇到的问题,但我真的很想看看是否有其他方法可以做到这一点(特别是使用 DI,因为我对这个主题真的很感兴趣)。

非常感谢所有做出贡献的人。

【讨论】:

  • 如果您想使用 IoC 容器检查 MVVM 框架,我用更多链接更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多