WPF中View与ViewModel分项目时如何实现依赖注入与懒加载
WPF MVVM 中DI实现单例ViewModel懒加载方案
问题现状
当前WPF项目采用分层结构:
MyApp |----MyApp.ViewModels |----MyApp.Views
按照微软依赖注入规范,DI容器在MyApp.Views项目的App.xaml.cs中初始化。ViewModel层定义了两个类型:
public class ViewModelAlpha{ private IDialogService _dialogService; private ViewModelBeta viewModelBeta; public ViewModelAlpha(IDialogService dialogService){ _dialogService = dialogService; } } public class ViewModelBeta{ private IDialogService _dialogService; public ViewModelBeta(IDialogService dialogService){ _dialogService = dialogService; } }
需求点:
ViewModelBeta需以单例形式存在ViewModelAlpha中需懒初始化ViewModelBeta,仅在实际使用时才实例化,避免提前占用资源- 原有思路是在
ViewModelBeta中实现静态Instance属性,尝试通过全局ServiceProvider获取单例,但ServiceProvider定义在View层,ViewModel层无法直接访问。
正确实现方式
绝对不要在ViewModel层直接引用全局ServiceProvider,这是典型的服务定位器反模式,会破坏分层依赖、提升单元测试难度、导致服务生命周期失控。
微软内置DI容器原生支持单例生命周期+懒加载能力,不需要手动实现静态单例,也不需要跨项目传递ServiceProvider,两步即可完成需求:
1. 服务注册时指定生命周期
在App.xaml.cs的DI初始化逻辑中,按如下规则注册类型:
// 注册基础服务 services.AddSingleton<IDialogService, DialogService>(); // ViewModelBeta注册为单例,容器全局仅生成一个实例 services.AddSingleton<ViewModelBeta>(); // ViewModelAlpha生命周期可根据实际业务需求选择瞬时/单例 services.AddTransient<ViewModelAlpha>();
2. 注入Lazy<T>实现懒加载
直接在ViewModelAlpha的构造函数中注入Lazy<ViewModelBeta>类型参数,DI容器会自动完成注入。只有当代码第一次访问Lazy.Value属性时,才会触发ViewModelBeta的实例化,完全符合懒加载要求,且获取到的就是容器管理的单例对象。
修改后的ViewModelAlpha代码:
public class ViewModelAlpha{ private readonly IDialogService _dialogService; private readonly Lazy<ViewModelBeta> _viewModelBeta; public ViewModelAlpha(IDialogService dialogService, Lazy<ViewModelBeta> viewModelBeta) { _dialogService = dialogService; _viewModelBeta = viewModelBeta; } // 实际需要使用ViewModelBeta的业务逻辑中,通过Value访问实例 public void ExecuteFeatureDependentOnBeta() { ViewModelBeta beta = _viewModelBeta.Value; // 执行业务逻辑 } }
方案说明
- 线程安全:内置DI注入的
Lazy<T>默认采用LazyThreadSafetyMode.ExecutionAndPublication模式,多线程场景下首次访问也仅会生成一个实例,匹配单例的线程安全要求 - 无额外耦合:ViewModel层不需要引用View层的任何代码,完全符合MVVM分层规范
- 可测试性强:单元测试时可以直接传入自定义的
Lazy<ViewModelBeta>实例,不需要Mock静态属性或者全局ServiceProvider - 生命周期托管:
ViewModelBeta的实例化、销毁完全由DI容器统一管理,不会出现手动实现单例时依赖未初始化、内存泄漏等问题
内容的提问来源于stack exchange,提问作者Nowayout
相关产品推荐
相关产品推荐

