You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解析.NET依赖注入中工厂委托自动解析对象的实现原理

关于Microsoft.Extensions.DependencyInjection中INavigationService注册逻辑的解析

针对你提出的三个疑惑,结合给出的代码逐一解析:

1. type => sp.GetRequiredService(type)为何是Func<Type, object>类型?参数type的含义是什么?

  • Func<Type, object>是.NET内置的委托类型,定义为接收一个Type类型参数,返回object类型结果的方法签名。你看到的lambda表达式type => sp.GetRequiredService(type)完全符合这个签名:输入一个Type,输出从DI容器获取的对象实例,因此可以直接赋值给这个委托类型。
  • 参数type代表你需要从DI容器中获取的服务类型,这里特指ViewModel的类型(比如HomeViewModel、MainViewModel)。当调用NavigateTo<T>()时,type就是typeof(T)的结果。

2. 如何通过type解析出对应的对象实例?

这依赖于Microsoft.Extensions.DependencyInjection的核心服务查找机制:

  1. 在App构造函数中,你已经通过_services.AddSingleton<MainViewModel>()这类方法,把ViewModel类型注册到了DI容器的服务注册表中,容器会记录每个类型对应的实例(单例模式下)或创建逻辑。
  2. 当调用sp.GetRequiredService(type)时,DI容器会:
    • 在内部注册表中查找与传入type匹配的服务;
    • 如果是单例服务,直接返回已创建好的实例;如果是其他生命周期(Scoped/Transient),则按注册逻辑创建新实例;
    • 如果找不到匹配的服务,直接抛出异常(这是GetRequiredService和GetService的核心区别,后者会返回null)。

3. 拆解整个代码的运行机制

把流程分成DI容器初始化和导航时的服务解析两个阶段来看:

阶段1:DI容器初始化(App构造函数)

  1. 注册单例ViewModel:_services.AddSingleton<MainViewModel>()和_services.AddSingleton<HomeViewModel>(),DI容器会为这两个类型创建单例实例并存储。
  2. 注册INavigationService:
    • 使用工厂委托sp => new NavService(type => sp.GetRequiredService(type)),其中sp是DI容器构建后的IServiceProvider实例;
    • 这里把sp.GetRequiredService包装成Func<Type, object>委托,传递给NavService的构造函数,让NavService拥有间接调用DI容器获取服务的能力,同时避免直接依赖DI容器本身。

阶段2:导航时的ViewModel解析(调用NavigateTo<T>())

  1. 当调用NavigateTo<HomeViewModel>()时,方法内部通过typeof(T)获取HomeViewModel的Type对象;
  2. 调用factory.Invoke(type),也就是执行sp.GetRequiredService(typeof(HomeViewModel));
  3. DI容器根据HomeViewModel类型,返回之前注册的单例实例;
  4. 把获取到的ViewModel赋值给CurrentView,触发OnPropertyChanged()通知UI更新,完成导航。

核心设计思路

这段代码通过委托实现了解耦:NavService不需要知道DI容器的具体实现,只需要通过Func<Type, object>委托就能获取ViewModel,同时复用了DI容器的生命周期管理(比如单例ViewModel的复用),符合依赖倒置原则。


内容的提问来源于stack exchange,提问作者Jess Chan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 22:20:40