.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.kler.cn/a/163503.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

修改移远提供的GobiNet、quectel-CM源码,使其支持有方N720 4G模块

最近在研究imx6ull linux下4G模块驱动的移植&#xff0c;参考的移远ec20的移植方法&#xff0c;添加了GobiNet驱动&#xff0c;编译了quectel-CM工具&#xff0c;并且可以正常拨号&#xff0c;分配到ip&#xff0c;如下&#xff1a; ping外网也没有压力&#xff0c;如下…

视频汇聚/音视频流媒体视频平台/视频监控EasyCVR分享页面无法播放,该如何解决?

国标GB28181安防视频监控/视频集中存储/云存储EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统…

分类信息发布小程序效果如何

信息发布系统连接信息供需双方&#xff0c;打造信息聚合平台&#xff0c;用户可获取和发布需求信息、参与互动交流&#xff0c;适用于同城、社区交流、客户互动、业务员/经纪人发布信息场景。 制作分类信息小程序后&#xff0c;商家后台设置信息项&#xff0c;发布者填写内容发…

TQ2440开发板-按键驱动程序设计

目录 按键测试底板原理图核心板原理图使用轮询方式设计按键程序 按键测试底板原理图 TQ2440开发板有4个用户可编程按键&#xff0c;它们直接与CPU的GPIO相连&#xff0c;低电平触发中断&#xff0c;资源占用如下图所示&#xff1a; 核心板原理图 使用轮询方式设计按键程序 按…

mmdetection测试保存到新的文件夹,无需标签

这个是用demo这个代码测试的&#xff0c;需要先训练一个pth文件夹&#xff0c;训练之后再调用pth文件夹进行测试。测试的代码文件名是&#xff1a;image_demo_new.py&#xff0c;代码如系所示&#xff1a; # Copyright (c) OpenMMLab. All rights reserved. import asyncio fr…

uni-app 设置tabBar的setTabBarBadge购物车/消息等角标

目录 一、效果二、代码实现二、全部代码1.index.vue2.cart.vue 三、真实案例参考最后 一、效果 二、代码实现 只要使用uni.setTabBarBadge和uni.removeTabBarBadge来进行对红点的设置和移除。 主要代码&#xff1a; //设置红点 uni.setTabBarBadge({index: 1, // 底部菜单栏…

Endnote使用教程

原由 最近要进行开题报告&#xff0c;要求不低于60文献的阅读与引用&#xff0c;单独插入引入我觉得是非常繁琐的事情&#xff0c;所以就借助Endnote这个工具&#xff0c;减少我们的工作量。 使用方法 第一步&#xff1a;先新建一个数据库&#xff0c;这样子可以在这个数据库…

【数据结构】——队列实现二叉树的功能

前言&#xff1a;二叉树的实现方式多种多样&#xff0c;有数组实现满二叉树&#xff0c;有链表实现完全二叉树&#xff0c;今天我们就用队列来实现二叉树。 创建二叉树&#xff1a; typedef int BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTre…

Linux信息收集

Linux信息收集 本机基本信息 #管理员 $普通用户 之前表示登录的用户名称&#xff0c;之后表示主机名&#xff0c;再之后表示当前所在目录 / 表示根目录 ~表示当前用户家目录1、内核&#xff0c;操作系统和设备信息 uname -a 打印所有可用的系统信息 uname -r 内核版本 u…

JS原生实现浏览器滚动条滚动侧边栏高亮响应

目录 演示 ​编辑 需求 代码 css html script 代码解释 1、获取所有link-content 2、定义一个rectContent数组&#xff0c;然后循环allContents调用getClientRects()[0]获取每个link-content元素与浏览器视口的关系 3、为数组追加link-content&#xff0c;用于设置侧…

深度学习在计算机视觉中的应用

深度学习在计算机视觉中的应用 摘要&#xff1a;本文介绍了深度学习在计算机视觉领域的应用&#xff0c;包括目标检测、图像分类、人脸识别等。通过分析深度学习在计算机视觉中的实际应用案例&#xff0c;阐述了深度学习在计算机视觉中的优势和未来发展趋势。 一、引言 计算…

基于Springboot+mybatis+mysql+jsp招聘网站

基于Springbootmybatismysqljsp招聘网站 一、系统介绍二、功能展示四、其他系统实现五、获取源码 一、系统介绍 项目类型&#xff1a;Java EE项目 项目名称&#xff1a;基于SPringBoot的照片网站 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语言 前端技术&…

数据可视化:解锁企业经营的智慧之道

在现代企业管理中&#xff0c;数据可视化已经成为了一项重要的工具。它不仅仅是简单地展示数据&#xff0c;更是提供了深入理解数据、做出更明智决策的方法。作为一名可视化设计从业人员&#xff0c;我经手过一些企业自用的数据可视化项目&#xff0c;今天就来和大家聊聊数据可…

快速认识什么是:Docker

Docker&#xff0c;一种可以将软件打包到容器中并在任何环境中可靠运行的工具。但什么是容器以及为什么需要容器呢&#xff1f;今天就来一起学快速入门一下Docker吧&#xff01;希望本文对您有所帮助。 假设您使用 Cobol 构建了一个在某种奇怪风格的 Linux 上运行的应用程序。您…

已发表的论文职称查重率高【详细说明】

大家好&#xff0c;今天来聊聊已发表的论文职称查重率高&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff1a; 已发表的论文职称查重率高 背景介绍 在学术界&#xff0c;论文的原创性和重复率是评价一篇论文质…

鸿蒙开发组件之Slider

一、Slider控件是鸿蒙开发中的滑动条组建&#xff0c;初始化方式 Slider({min:0, //最小值max:100,//最大值value:30,//默认值step:10,//步长&#xff0c;每次滑动的差值style:SliderStyle.OutSet, //滑块的样式&#xff0c;默认outsetdirection:Axis.Horizontal, //水平方式的…

【基于LicheePi-4A的 人脸识别系统软件设计】

参考:https://www.xrvm.cn/community/post/detail?spm=a2cl5.27438731.0.0.31d40dck0dckmg&id=4253195599836418048 1.前言 原先计划做基于深度学习的炸药抓取和智能填装方法研究,但是后来发现板卡不支持pyrealsense2等多个依赖包。因此改变策略,做一款基于LicheePi…

使用git出现的问题

保证 首先保证自己的git已经下载 其次保证自己的gitee账号已经安装并且已经生成ssh公钥 保证自己要push的代码在要上传的文件夹内并且配置文件等都在父文件夹&#xff08;也就是文件没有套着文件&#xff09; 问题 1 $ git push origin master gitgitee.com: Permission de…

蒙特霍尔问题(选择三扇门后的车与羊)及其贝叶斯定理数学解释

1. 蒙特霍尔问题 有一个美国电视游戏节目叫做“Let’s Make a Deal”&#xff0c;游戏中参赛者将面对3扇关闭的门&#xff0c;其中一扇门背后有一辆汽车&#xff0c;另外两扇门后是山羊&#xff0c;参赛者如果能猜中哪一扇门后是汽车&#xff0c;就可以得到它。 通常&#xf…

quickapp_快应用_快应用与h5交互

快应用与h5交互 h5跳转到快应用[1] 判断当前环境是否支持组件跳转快应用[2] h5跳转到快应用(1)deeplink方式进行跳转(推荐)(2)h5点击组件(接收参数存在问题)(3)url配置跳转(官方不推荐) 问题-浏览器问题 web组件h5页面嵌入快应用快应用发送消息到h5页面h5页面接收快应用发送的消…
最新文章