.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection

文章目录

  • 前言
  • 什么是依赖注入
  • C# 使用依赖注入
    • 框架介绍
  • Microsoft.Extensions.DependencyInjection
    • Nuget安装
    • 简单单例使用
      • 打印结果
    • 自动装配
      • 举例
      • 自动装配测试用例
      • 打印结果
      • 自动装配执行顺序
        • 测试用例
        • 有歧义构造函数
        • 渐进式构造函数
        • 循环依赖
      • 自动装配结论
    • 手动装配
      • 手动注入
      • 别名注入
    • 依赖注入的构造顺序
  • 结尾

前言

依赖注入是一个非常重要的编程思想,就和面向过程和面向对象一样,IOC和控制反转是一种解耦的编程思想。

什么是依赖注入

[C#]理解和入门依赖注入

为什么要用IOC:inversion of controll反转控制(把创建对象的权利交给框架)

C# 使用依赖注入

框架介绍

目前.NET 有两个最优的依赖注入框架

  • Microsoft.Extensions.DependencyInjection:微软官方依赖注入框架,听说在.net core 8.0得到了最强的性能提升
  • Autofac:听说也是最强的依赖注入框架,性能强,开销低,功能完善。

Dependency injection in ASP.NET Core

Autofac 官网

深入浅出依赖注入容器——Autofac

Microsoft.Extensions.DependencyInjection

目前打算用微软的IOC,毕竟是官方背书,性能有保证。

C# 依赖注入IServiceCollection的AddSingleton方法使用

Nuget安装

在这里插入图片描述

简单单例使用

声明个测试类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace NETCore8.Models
{public class Person{public int Id { get; set; }public string ?Name { get; set; }public int Age { get; set; }}
}

主函数代码

using Microsoft.Extensions.DependencyInjection;
using NETCore8.Models;
using Newtonsoft.Json;
using System.ComponentModel.Design;namespace NETCore8
{internal class Program{static void Main(string[] args){//构造依赖注入容器IServiceCollection services = new ServiceCollection();//注入Person单例,生命周期暂时不展开services.AddSingleton<Person>();var builder = services.BuildServiceProvider();//初始化单例var res = builder.GetService<Person>();res.Name = "小刘";res.Age = 15;Console.WriteLine(JsonConvert.SerializeObject(res));//从容器中拿到Person单例,确认是否已被赋值为小刘var res2 = builder.GetService<Person>();Console.WriteLine(JsonConvert.SerializeObject(res2));//修改单例,查看容器中的单例是否被修改res2.Name = "小红";res2.Age = 23;//再从容器中拿出单例var res3 = builder.GetService<Person>();Console.WriteLine(JsonConvert.SerializeObject(res3));Console.WriteLine("Hello, World!");Console.ReadKey();}}
}

打印结果

在这里插入图片描述
这个说明这个单例一旦被修改了,容器中的数据就会被修改。但是这样仅仅是和全局静态的效果一样。依赖注入没有这么简单

自动装配

自动装配的意思就是自动依赖注入。就是你不需要主动去声明构造函数,IOC容器会自动帮你去使用构造函数。

举例

这里为了简单说明,这里只使用单例自动装配举例。

namespace IOC_Test.Models
{public class Person{public int Id { get; set; }public string Name { get; set; }public int Age {  get; set; }   }
}
namespace IOC_Test.Services
{public class PersonService{public Person Person { get; set; }/// <summary>/// 无参构造函数/// </summary>public PersonService() {Person = new Person();}/// <summary>/// 有参构造函数,IOC是选择尽可能多的参数构造/// </summary>/// <param name="person"></param>public PersonService(Person person){this.Person = person;}}
}

自动装配测试用例

using IOC_Test.Models;
using IOC_Test.Services;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;namespace IOC_Test
{internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();//注入依赖services.AddSingleton<Person>();services.AddSingleton<PersonService>();//生成IOC容器var builder = services.BuildServiceProvider();//两次打印,第一次打印PersonService的Person{var res = builder.GetService<PersonService>();Console.WriteLine(JsonConvert.SerializeObject(res?.Person));}//修改Person,看看PersonService里面是不是会受影响{var res = builder.GetService<Person>();res.Name = "小王";res.Age = 10;}//再次打印,如果被修改,那么就说明是自动装配。如果没被修改,就说明没有将Person自动注入到PersonService{var res = builder.GetService<PersonService>();Console.WriteLine(JsonConvert.SerializeObject(res?.Person));}Console.WriteLine("Hello, World!");Console.ReadLine();}}
}

打印结果

在这里插入图片描述

自动装配执行顺序

测试用例

这里我们新建一个Dog

namespace IOC_Test.Models
{public class Dog{public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }}
}

Person

namespace IOC_Test.Models
{public class Person{public int Id { get; set; }public string Name { get; set; }public int Age {  get; set; }   }
}

PersonService

namespace IOC_Test.Services
{public class PersonService{public Person Person { get; set; }public Dog Dog { get; set; }/// <summary>/// 无参构造函数/// </summary>public PersonService() {Person = new Person();}}
}

主函数

namespace IOC_Test
{internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();//注入依赖services.AddSingleton<Person>();services.AddSingleton<PersonService>();services.AddSingleton<Dog>();//生成IOC容器var builder = services.BuildServiceProvider();//两次打印,第一次打印PersonService{var res = builder.GetService<PersonService>();Console.WriteLine(JsonConvert.SerializeObject(res));}//修改Person和Dog,看看PersonService里面是不是会受影响{var person = builder.GetService<Person>();person.Name = "小王";person.Age = 10;var dog = builder.GetService<Dog>();dog.Name = "旺财";dog.Age = 2;}//再次打印,查看自动装配如何执行{var res = builder.GetService<PersonService>();Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}}
}
有歧义构造函数
namespace IOC_Test.Services
{public class PersonService{public Person Person { get; set; }public Dog Dog { get; set; }/// <summary>/// 无参构造函数/// </summary>public PersonService() {Person = new Person();}public PersonService(Person person){this.Person = person;}public PersonService(Dog dog) {this.Dog = dog;}}
}

如果构造函数出现歧义,比如这里既可以选择Person构造,又可以选择Dog构造,会报错
在这里插入图片描述

渐进式构造函数
namespace IOC_Test.Services
{public class PersonService{public Person Person { get; set; }public Dog Dog { get; set; }/// <summary>/// 无参构造函数/// </summary>public PersonService() {Person = new Person();}public PersonService(Person person){this.Person = person;}public PersonService(Person person,Dog dog) {this.Person= person;this.Dog = dog;}}
}

运行成功
在这里插入图片描述

循环依赖

Person注入Dog,Dog注入Person,看看效果如何

namespace IOC_Test.Models
{public class Person{public Dog Dog { get; set; }public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }public Person(Dog dog){Dog = dog;}}
}
namespace IOC_Test.Models
{public class Dog{public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }public Person Person { get; set; }public Dog(Person person){Person = person;}}
}

在这里插入图片描述

自动装配结论

自动装配是尽可能主动去装配服务,如果出现装配歧义,循环依赖,那么就会主动抛出异常。自动装配可以极大的减少对构造函数维护,我们不需要知道服务是怎么声明的,IOC容器会帮助我们自动声明相互之间的依赖。这张图就能很好的解释自动装配的效果

在这里插入图片描述

手动装配

自动装配是由IOC容器自动装配的类。如果需要装配多个同类的服务,那就要手动进行区别了。

手动注入

internal class Program
{static void Main(string[] args){IServiceCollection services = new ServiceCollection();services.AddSingleton<Person>(sp =>{var res = new Person() {Name = "小红",Age = 19};return res;});//生成容器var builder = services.BuildServiceProvider();{var res = builder.GetService<Person>();Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}
}

在这里插入图片描述

别名注入

namespace IOC_Test
{internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();services.AddKeyedSingleton<Person>("A",(sp,key) =>{var res = new Person() {Name = "小红",Age = 19};return res;});services.AddKeyedSingleton<Person>("B", (sp, key) =>{var res = new Person(){Name = "小蓝",Age = 23};return res;});//生成容器var builder = services.BuildServiceProvider();//获取服务,当Key找不到时自动返回Null{var res = builder.GetService<Person>();Console.WriteLine("获取默认服务");Console.WriteLine(JsonConvert.SerializeObject(res));}{var res = builder.GetKeyedService<Person>("A");Console.WriteLine("获取A,Person");Console.WriteLine(JsonConvert.SerializeObject(res));}{var res = builder.GetKeyedService<Person>("B");Console.WriteLine("获取B,Person");Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}}
}

在这里插入图片描述

声明别名的服务将不会自动装配,即使声明的别名相同。建议使用多个不同名的服务来自动装配。手动声明别名需要手动装配对应关系

也可以在输入的时候主动拿到按照Key去寻找服务。

internal class Program
{static void Main(string[] args){IServiceCollection services = new ServiceCollection();//依赖注入是使用的时候去构造,所以声明顺序不影响实际运行顺序,有点类似于回调函数services.AddKeyedSingleton<Person>("A",(sp,key) =>{//Console.WriteLine(key);var res = new Person() {Name = "小红",Age = 19};return res;});services.AddKeyedSingleton<PersonService>("A", (sp, key) =>{return new PersonService(sp.GetKeyedService<Person>(key));});//生成容器var builder = services.BuildServiceProvider();//获取服务{var res = builder.GetKeyedService<Person>("A");Console.WriteLine("获取默认服务");Console.WriteLine(JsonConvert.SerializeObject(res));}//获取服务{var res = builder.GetKeyedService<PersonService>("A");Console.WriteLine("获取默认服务");Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}
}

依赖注入的构造顺序

依赖注入是使用的时候去生成,而不是注入的时候生成

namespace IOC_Test
{internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();services.AddKeyedSingleton<Person>("A",(sp,key) =>{Console.WriteLine($"构造函数执行,key[{key}]");var res = new Person() {Name = "小红",Age = 19};return res;});//生成容器var builder = services.BuildServiceProvider();//获取服务{Console.WriteLine("获取Key[A]服务");var res = builder.GetKeyedService<Person>("A");Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}}
}

在这里插入图片描述

结尾

IOC容器还有许多别的功能,比如别名,接口注入,注解注入,声明周期等。这个我还不太了解。现在的单例自动装配已经基本满足了我的功能,我以后有时间会去深入了解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/210789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

调用win32 api获取电脑名字和系统目录

学习一下几个函数的功能&#xff0c;和调用方式&#xff1b; void CBasenameView::OnDraw(CDC* pDC) {CBasenameDoc* pDoc GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCString str1;TCHAR myname1[50], myname2[50], mydirname1[50], myd…

常见的Linux系统版本

在介绍常见的Linux系统版本之前&#xff0c;首先需要区分Linux系统内核与Linux发行套件系统的不同。Linux系统内核指的是一个由Linus Torvalds负责维护&#xff0c;提供硬件抽象层、硬盘及文件系统控制及多任务功能的系统核心程序。而Linux发行套件系统是我们常说的Linux操作系…

【Vue+Python】—— 基于Vue与Python的图书管理系统

文章目录 &#x1f356; 前言&#x1f3b6;一、项目描述✨二、项目展示&#x1f3c6;三、撒花 &#x1f356; 前言 【VuePython】—— 基于Vue与Python的图书管理系统 &#x1f3b6;一、项目描述 描述&#xff1a; 本项目为《基于Vue与Python的图书管理系统》&#xff0c;项目…

Minio保姆级教程

转载自&#xff1a;www.javaman.cn Minio服务器搭建和整合 1、centos安装minio 1.1、创建安装目录 mkdir -p /home/minio1.2、在线下载minio #进入目录 cd /home/minio #下载 wget https://dl.minio.io/server/minio/release/linux-amd64/minio1.3、minio配置 1.3.1、添加…

Flutter笔记:滑块及其实现分析1

Flutter笔记 滑块分析1 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/134900784 本文从设计角度&#…

SQL命令---删除字段

介绍 使用sql语句删除表字段。 命令 alter table 表名 drop 字段名;例子 删除a表中的name字段。 alter table a drop name;下面是执行删除后的表结构&#xff1a;

微服务实战系列之通信

前言 掰个指头数一数&#xff0c;博主的“微服务实战系列”从无到有&#xff0c;从零走到了十五。如果比作时钟&#xff0c;刚好走过了一刻度。 当初为什么要做这个系列&#xff0c;博主想了又想&#xff0c;私以为作为当下软件领域的几个“hot spot”之一&#xff0c;又乘着…

探秘机器学习核心逻辑:梯度下降的迭代过程 (图文详解)

一 需求解函数 f() 和 g()函数分别为求y值和求导数的函数。 目的&#xff1a;求该函数的最小值&#xff1a; 代码&#xff1a; import numpy as np import matplotlib.pyplot as plt f lambda x : (x - 3.5) ** 2 - 4.5 * x 10 g lambda x : 2 * (x - 3.5) - 4.5x np.l…

架构LAMP

目录 1.什么是LAMP 2.LAMP组成及作用 3.搭建Apache httpd服务 4.编译安装mysqld 服务 5.编译安装PHP 解析环境 6.安装论坛 1.什么是LAMP LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务…

【Python】视频剪辑小程序

近期遇到一些录制的视频需要剪辑。 手机上剪辑操作很耗时&#xff0c;有几个G的视频&#xff0c;花了一天的空余时间去剪辑。电脑上也有格式工厂&#xff0c;有很方便。 可是学了Pthon&#xff0c;又无意中了解到了moviepy这个库&#xff0c;于是自己写了个简单的视频剪辑程序。…

Windows安装kafka

压缩包下载地址&#xff1a;https://www.apache.org/dyn/closer.cgi?path/kafka/3.6.1/kafka_2.13-3.6.1.tgz 启动kafka步骤 zookeeper-server-start.bat rem 闭命令提示符窗口的命令回显&#xff0c;这样在运行脚本时不会显示脚本的具体命令内容 echo offrem 命令行启动未…

Proteus仿真--8×8LED点阵屏仿电梯数字滚动显示

本文介绍基于88LED点阵屏仿电梯数字滚动显示设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 其中K1-K5的5个按键分别代表不同楼层&#xff0c;摁下按键后在8X8LED上便会显示到对应楼层的跳变信息&#xff0c;模拟电梯的运作 仿真运行视频 Proteus仿…

《安富莱嵌入式周报》第328期:自主微型机器人,火星探测器发射前失误故障分析,微软推出12周24期免费AI课程,炫酷3D LED点阵设计,MDK5.39发布

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新一期视频教程&#xff1a; 【实战技能】 单步运行源码分析&#xff0c;一期视频整明白FreeRTOS内核源码框架和运行…

【STM32】TIM定时器基本定时功能

第一部分&#xff1a;定时器基本定时的功能&#xff1b; 第二部分&#xff1a;定时器的输出比较功能&#xff1b; 第三部分&#xff1a;定时器输入捕获的功能&#xff1b; 第四部分&#xff1a;定时器的编码接口。 1 TIM简介 TIM&#xff08;Timer&#xff09;定时器&#…

在OpenCV基于深度学习的超分辨率模型实践

1. 引言 OpenCV是一个开源的计算机视觉库&#xff0c;拥有大量优秀的算法。基于最新的合并&#xff0c;OpenCV包含一个易于使用的接口&#xff0c;主要用于实现基于深度学习方法的超分辨率&#xff08;SR&#xff09;。该接口包含预先训练的模型&#xff0c;这些模型可以非常容…

redis中使用事务保护数据完整性

事务是指一个执行过程&#xff0c;要么全部执行成功&#xff0c;要么失败什么都不改变。不会存在一部分成功一部分失败的情况&#xff0c;也就是事务的ACID四大特性&#xff08;原子性、一致性、隔离性、持久性&#xff09;。但是redis中的事务并不是严格意义上的事务&#xff…

智能优化算法应用:基于蝗虫算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝗虫算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝗虫算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝗虫算法4.实验参数设定5.算法结果6.参考文献7.MA…

持续集成交付CICD:使用Maven命令上传Nexus制品

目录 一、实验 1.使用Maven命令上传Nexus制品&#xff08;第一种方式&#xff09; 2.使用Maven命令上传Nexus制品&#xff08;第二种方式&#xff09; 一、实验 1.使用Maven命令上传Nexus制品&#xff08;第一种方式&#xff09; &#xff08;1&#xff09;指定一个 hoste…

Flutter视频播放器在iOS端和Android端都能实现全屏播放

Flutter开发过程中&#xff0c;对于视频播放的三方组件有很多&#xff0c;在Android端适配都挺好&#xff0c;但是在适配iPhone手机的时候&#xff0c;如果设置了UIInterfaceOrientationLandscapeLeft和UIInterfaceOrientationLandscapeRight都为false的情况下&#xff0c;无法…

基于PaddleOCR银行卡识别实现(四)之uni-app离线插件

目的 在前三篇文章中完成了银行卡识别整个模型训练等工作&#xff0c;通过了解PaddleOCR的端侧部署&#xff0c;我们也可以将银行卡号检测模型和识别模型移植到手机中&#xff0c;做成一款uni-app手机端离线银行卡号识别的应用。 准备工作 为了不占用过多篇幅&#xff0c;这…