如何从类库访问泛型主机服务?WinUI3依赖注入场景
最优实现方案
完全不需要使用反射,核心思路是避免类库反向依赖主应用的具体App类实现,通过公共抽象契约完成解耦,方案稳定可维护,不会因为主应用内部字段、类名修改出现运行时崩溃。
第一步:在公共共享层定义服务访问契约
新建一个所有独立文档类库、主应用都会引用的轻量公共类库(如果不想单独建项目,也可以把这段代码放到现有被各方共同引用的公共项目中),定义静态服务访问包装类:
// 放在公共引用项目中,所有独立类库可直接访问 public static class ServiceLocator { private static IServiceProvider? _serviceProvider; // 主应用初始化泛型主机时仅需调用一次,注入服务提供器实例 public static void Init(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public static T? GetService<T>() where T : class { return _serviceProvider?.GetService(typeof(T)) as T; } public static object? GetService(Type serviceType) { return _serviceProvider?.GetService(serviceType); } }
注意:不要把这个类定义在主应用项目内,必须放在所有插件类库可直接引用的公共层,从根源消除对主应用私有实现的依赖。
第二步:主应用初始化Host时完成契约注册
在主应用App.xaml.cs中,泛型主机构建完成后,仅需加一行代码完成服务提供器的注入,你原有主应用内部的DI调用逻辑完全不需要改动:
public App() { this.InitializeComponent(); // 保留你原有的泛型主机初始化逻辑 Host = BuildMyAppHost(); // 新增这一行初始化公共服务定位器 ServiceLocator.Init(Host.Services); } // 原有主应用的Host静态属性可以完全保留 public static IHost Host { get; private set; }
第三步:独立类库中直接调用契约获取视图模型
把类库中原有的反射代码全部替换为强类型调用即可,代码更简洁,编译期即可检查错误:
// 独立类库页面后台代码中,替换原有反射逻辑 ViewModel = ServiceLocator.GetService<SetupDataViewModel>();
进阶优化方案(完全符合MVVM规范,无需静态服务定位器)
如果项目后续扩展的文档类型较多,可以从导航层改造彻底解决依赖问题:
- 重写WinUI3默认的Frame导航逻辑,实现支持DI的导航扩展,导航时自动从服务容器解析页面实例
- 主应用启动时通过程序集扫描,把所有独立类库中的页面、视图模型批量注册到Host的服务集合中
- 导航时自动为页面注入对应视图模型,页面后台不需要手写任何获取服务的代码,完全消除静态依赖,更方便做单元测试
对比反射方案的优势
- 无反射的性能开销,不会因为主应用修改私有字段名
_host、类名SWFieldData.App就触发运行时异常 - 所有调用都是强类型,编译期即可做错误检查,不需要硬编码反射用的类型名、属性名字符串
- 类库和主应用完全解耦,类库不需要感知主应用App类的内部实现,后续调整主应用启动逻辑时不需要修改类库代码
内容的提问来源于stack exchange,提问作者Russ_S
相关产品推荐
相关产品推荐

