当前位置: 首页 > news >正文

.NET依赖注入IOC你了解吗?

IOC在Web API 中是经常使用的,但是在一些WPF项目并不是经常使用或者被人熟知的,我把相关依赖注入的内容又做了一次学习和整理

什么是依赖注入?

依赖注入是一种设计模式和软件设计原则,用于实现 控制反转。它的核心思想是:将对象所依赖的其他对象的创建和管理职责从对象内部转移到外部容器或框架,从而降低代码的耦合度,提高可测试性、可维护性和灵活性。

依赖注入的主要优点

  1. 降低耦合度(Decoupling):
    ○ 组件(如 OrderService)只依赖于接口(如 IOrderRepository),而不依赖于具体实现(如 SqlOrderRepository)。具体实现的切换由外部容器控制。
  2. 提高可测试性(Testability):
    ○ 可以轻松地为依赖项创建 Mock 或 Stub 对象(实现相同的接口),并在测试时注入到被测试对象中。这使得单元测试独立、快速且可靠(不依赖数据库、网络等外部资源)。
  3. 提高可维护性和可扩展性:
    ○ 更容易替换依赖的实现(只需在容器配置中更改绑定关系)。
    ○ 更容易添加新功能(添加新实现并注册到容器即可)。
    ○ 代码更清晰,职责更单一。
  4. 促进代码重用:
    ○ 解耦后的组件更容易在不同的上下文中复用。
  5. 管理对象生命周期:
    ○ DI 容器通常提供对依赖对象生命周期的管理(如单例、每次请求创建新实例、线程内单例等),简化了资源管理。

NET 项目使用依赖注入

● Microsoft.Extensions.DependencyInjection.Abstractions
● Microsoft.Extensions.Dependencyinjection

核心类型

● IServiceCollection 服务注册
● ServiceDescriptor 服务注册时的信息
● IServiceProvider 具体的容器
● IServiceScope 子容器生命周期

生命周期

1.AddSingleton 单例生命周期

● 在整个进程中,多次创建对象都是同一个对象—遵循了单例模式;
● 第一次创建以后,在内存中,保存下来了,下次创建–直接使用内存,而不是再去全新的创建

ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddSingleton<ITestService, TestService>();
ServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();ITestService testService1 = serviceProvider.GetService<ITestService>();
ITestService testService2 = serviceProvider.GetService<ITestService>();bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2   {isflg}"); //true

2.AddScoped 作用域生命周期

● 每一个作用域(serviceProvider)内创建的某一个类的对象是同一个实例
● 不同的作用域(serviceProvider)内创建的同一个类的对象是不同的实例
● 这种⽣命周期适⽤于需要在特定作⽤域内共享对象实例的情 况,⽐如Web应⽤程序中的每个HTTP请求

ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddScoped<ITestService, TestService>();
ServiceProvider serviceProvider1 = serviceDescriptors.BuildServiceProvider();ITestService testService1 = serviceProvider1.GetService<ITestService>();
ITestService testService2 = serviceProvider1.GetService<ITestService>();
bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2   {isflg}");//trueServiceProvider serviceProvider2 = serviceDescriptors.BuildServiceProvider();
ITestService testService3 = serviceProvider2.GetService<ITestService>();
ITestService testService4 = serviceProvider2.GetService<ITestService>();
bool isflg1 = object.ReferenceEquals(microphone3, microphone4);
Console.WriteLine($"testService3==testService4   {isflg1}");//truebool isflg2 = object.ReferenceEquals(testService1, testService3);
Console.WriteLine($"microphone1==microphone3   {isflg2}");//false

3.AddTransient 瞬时生命周期

● 每一次都会创建出一个全新的实例
● 如果需要每次都创建实例—瞬时

ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddTransient<ITestService, Microphone>();
ServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();
ITestService testService1 = serviceProvider.GetService<ITestService>();
ITestService testService2 = serviceProvider.GetService<ITestService>();
bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2   {isflg}"); //fals

依赖注入方式

1.构造函数注入

在执行构造函数的时候,能够把构造函数依赖的参数自动构造出来,传递进来;–无限层级

public class MainViewModel
{private readonly ITestService _testService;public MainViewModel(ITestService testService){this._testService = testService;}
}

2.属性注入

在某个类的内部包含的有属性,在构造出整个类的时候,这个类中的某些属性,能够自动根据属性的类型–自动构造出实例–赋值给属性;
官方不支持需要引入第三方框架

public class MainViewModel
{[Inject]public ITestService TestService { get; set; }public MainViewModel(){}
}

3.方法注入

在某个类的内部,包含的有一些特殊的方法,在构造这个类的实例的时候,能够自动的把方法执行掉,方法需要的参数—自动构建实例,传递进来;
• [FromServices] 需要引用 NuGet 包:Microsoft.AspNetCore.Mvc(仅限 ASP.NET Core 项目)。

public class MainViewModel
{public MainViewModel(){}public void Test([FromServices] ITestService testService){testService.GetMessage();}
}

原生WPF项目使用IOC

public partial class App : Application
{public static App CurrentApp { get; private set; } = null!;public App(){CurrentApp = this;}public IServiceProvider ServiceProvider { get; set; } = null!;protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);var serviceCollection = new ServiceCollection();ConfigureServices(serviceCollection);this.ServiceProvider = serviceCollection.BuildServiceProvider();var mainWindow = this.ServiceProvider.GetService<MainWindow>();mainWindow?.Show();}private void ConfigureServices(IServiceCollection services){services.AddSingleton<MainWindow>();services.AddSingleton<MainViewModel>();services.AddTransient<ITestService, TestService>();}
}
public partial class MainWindow : Window{public MainWindow(){InitializeComponent();this.DataContext = App.CurrentApp.ServiceProvider.GetService(typeof(MainViewModel));}
}
http://www.lryc.cn/news/594619.html

相关文章:

  • 智能体性能优化:延迟、吞吐量与成本控制
  • 机器阅读理解(MRC)全面解析:任务分类、评估指标与57个数据集资源盘点
  • Nacos安装单例模式
  • 西门子 SIMATIC S7-1500 数字量输入模块:深度剖析与应用指南
  • ABQ-LLM:用于大语言模型的任意比特量化推理加速
  • Zabbix 企业级分布式监控系统深度解析
  • Android 单编 framework 相关产物输出介绍
  • 3.组合式API父子通信
  • OpenAI开发的一款实验性大型语言模型(LLM),在2025年国际数学奥林匹克竞赛(IMO)中达到了金牌水平
  • 什么是商业智能BI数据分析的指标爆炸?
  • 悬镜安全将受邀参加2025开放原子开源生态大会
  • “融合进化,智领未来”电科金仓引领数字化转型新纪元
  • FFmpeg:数字媒体的终极瑞士军刀
  • ssms(SQL 查询编辑器) 添加快捷键 Ctrl+D(功能等于Ctrl+C + Ctrl+V),一步到位
  • 【PTA数据结构 | C语言版】列出连通集
  • 第三章自定义检视面板_创建自定义编辑器类_如何自定义预览窗口(本章进度5/9)
  • C++基于libmodbus库实现modbus TCP/RTU通信
  • 个人中心产品设计指南:从信息展示到用户体验的细节把控
  • 第三章自定义检视面板_创建自定义编辑器类_编扩展默认组件的显示面板(本章进度3/9)
  • Jenkins 不同节点间文件传递:跨 Job 与 同 Job 的实现方法
  • 修复echarts由4.x升级5.x出现地图报错echarts/map/js/china.js未找到
  • 人形机器人CMU-ASAP算法理解
  • QGIS、ArcMap、ArcGIS Pro中的书签功能、场景裁剪
  • ruoyi-flowable-plus Excel 导入数据 Demo
  • 现在希望用git将本地文件test目录下的文件更新到远程仓库指定crawler目录下,命名相同的文件本地文件将其覆盖
  • 自动驾驶中各传感器的优缺点
  • 一个月掌握数据结构与算法:高效学习计划
  • uni-app 鸿蒙平台条件编译指南
  • vxe-table 通过配置 ajax 方式自动请求数据,适用于简单场景的列表
  • 网络基础1-11综合实验(eNSP):vlan/DHCP/Web/HTTP/动态PAT/静态NAT