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

.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.xdnf.cn/news/15895.html

相关文章:

  • 14.6 《3步实战LLaMA2-7B指令微调:Hugging Face生态+LoRA技术,MT-Bench得分从5.1直升7.3》
  • 基于爬虫技术的电影数据可视化系统 Python+Django+Vue.js
  • C# 集合(Collection)
  • Playwright-MCP浏览器会话复用全解析
  • 企业管理效能提升之道——固定资产管理的价值体现
  • Flutter和Kotlin的对比
  • 北京-4年功能测试2年空窗-报培训班学测开-第五十六天
  • 【Docker#3】Window 和 Linux 上 docker安装 相关知识
  • 算法训练营day25 回溯算法④ 补充联系题目 332.重新安排行程、51. N皇后、37. 解数独
  • 【详细笔记】两类曲线积分转换
  • 14.多播与广播
  • ESMFold 安装教程
  • Linux主机 ->多机器登录
  • 尚庭公寓--------登陆流程介绍以及功能代码
  • PostgreSQL 字段类型速查与 Java 枚举映射
  • XSS的介绍
  • LWJGL教程(3)——时间
  • JWT原理及利用手法
  • 基于单片机倾角测量仪/角度测量/水平仪
  • spring-ai-alibaba如何上传文件并解析
  • 【高等数学】第四章 不定积分——第四节 有理函数的积分
  • 元学习算法的数学本质:从MAML到Reptile的理论统一与深度分析
  • 人脸识别:AI 如何精准 “认人”?
  • 【新手向】PyTorch常用Tensor shape变换方法
  • Spring Boot 订单超时自动取消的 3 种主流实现方案
  • 响应式编程入门教程第九节:UniRx 高级特性与自定义
  • LeetCode|Day20|9. 回文数|Python刷题笔记
  • DOM型XSS破坏
  • PID控制原理分析及应用(稳态误差详细分析)(一)
  • 如何升级Docker部署的Dify