我正在 WPF 中构建一个类似 Visual Studio 的应用程序,但在确定组件的最佳架构设计组织时遇到了一些问题。我计划使用 Unity 作为我的依赖注入容器和 Visual Studio 单元测试框架,并且可能使用 moq 来模拟库。
我将首先描述我的解决方案的结构,然后是我的问题:
我有一个WPF 项目,其中包含:
- 应用程序启动时我的 Unity 容器初始化(引导程序)(在 App.xaml.cs 中)
- 我所有的应用程序视图 (XAML)。
另一个名为ViewModel的项目包含:
- 我所有的应用程序视图模型。我所有的 ViewModel 都继承自 ViewModelBase,它公开了 ILogger 属性
我的初始化逻辑如下:
- 应用程序启动
- Unity 容器创建和注册类型:MainView 和 MainViewModel
- 解决我的 MainView 并显示它。
var window = Container.Resolve<MainView>();
window.Show();
我的 MainView 构造函数在其构造函数中接收 MainViewModel 对象:
public MainView(MainViewModel _mvm)
我的 MainViewModel 的每个面板都有一个子 ViewModel:
public ToolboxViewModel ToolboxVM{get; set;} public SolutionExplorerViewModel SolutionExplorerVM { get; set; } public PropertiesViewModel PropertiesVM { get; set; } public MessagesViewModel MessagesVM { get; set; }
我计划创建一个 InitializePanels() 方法来初始化每个面板。
现在我的问题是:我的 MainViewModel.InitializePanels() 如何初始化所有这些面板?给出以下选项:
选项 1:手动初始化 ViewModel:
ToolboxVM = new ToolboxViewModel();
//Same for the rest of VM...
缺点:
- 我没有使用 Unity 容器,因此我的依赖项(例如 ILogger)不会自动解析
选项 2:通过注释我的属性来使用 setter 注入:
[Dependency]
public ToolboxViewModel ToolboxVM{get; set;}
//... Same for rest of Panel VM's
缺点:
- 我读过应该避免 Unity Setter 依赖项,因为在这种情况下它们会与 Unity 产生依赖关系
- 我还读到你应该避免使用 Unity 进行单元测试,那么如何在我的单元测试中明确这种依赖关系?拥有许多依赖属性可能是配置的噩梦。
选项 3:使用 Unity 构造函数注入将我的所有面板视图模型传递给 MainViewModel 构造函数,以便它们由 Unity 容器自动解析:
public MainViewModel(ToolboxViewModel _tbvm, SolutionExploerViewModel _sevm,....)
优点:
- 在创建时,依赖关系是显而易见的,这有助于构建我的 ViewModel 单元测试。
缺点:
- 拥有如此多的构造函数参数可能会很快变得丑陋
选项 4:在容器构建时注册我的所有 VM 类型。然后通过构造函数注入将 UnityContainer 实例传递给我的 MainViewModel:
public MainViewModel(IUnityContainer _container)
这样我可以做类似的事情:
Toolbox = _container.Resolve<ToolboxViewModel>();
SolutionExplorer = _container.Resolve<SolutionExplorerViewModel>();
Properties = _container.Resolve<PropertiesViewModel>();
Messages = _container.Resolve<MessagesViewModel>();
缺点:
- 如果我决定不将 Unity 用于我的单元测试,正如许多人所建议的那样,那么我将无法解析和初始化我的面板视图模型。
鉴于这个冗长的解释,什么是最好的方法,以便我可以利用依赖注入容器并最终得到一个可单元测试的解决方案?
提前致谢,