C# “依赖注入” 中的 “三种生命周期”

news/2024/5/19 22:43:30 标签: c#, .netcore, 依赖注入, 生命周期

🚀简介

依赖注入(Dependency Injection,简称DI)是一种实现控制反转(IoC)的技术,用于减少代码之间的耦合度。通过依赖注入,一个类可以从外部获取其依赖的对象,而不是自己创建。这样可以使得代码更加模块化,更易于测试和维护。

🐳依赖注入生命周期主要有以下三种:

  1. Transient:每次请求都会创建一个新的实例。这是最常见的生命周期选项。
  2. Scoped:在同一次请求中始终返回同一实例。如果在不同的请求中,将会创建一个新的实例。
  3. Singleton:每次请求都返回同一个实例,即在首次请求时创建的实例。

🚀安装NuGet包

首先,我们先安装 Microsoft.Extensions.DependencyInjection:这是Microsoft提供的依赖注入框架。

🚀Transient

创建一个类,包含一个属性(Name)和一个方法(SayHi)

public class TestServicesImp
{
    public string Name { get; set; }
    
    public void SayHi()
    {
        Console.WriteLine("Hello:"+Name);
    }
}

👻通过ServiceCollection创建了一个服务容器,然后通过AddTransient方法将TestServicesImp类型注册到这个服务容器中。这里使用的是瞬时生命周期,也就是每次从容器中获取TestServicesImp类型时,都会创建一个新的实例。

public class Program
{
    public static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddTransient<TestServicesImp>();
        using (ServiceProvider sp = serviceCollection.BuildServiceProvider())
        {
            var t1 = sp.GetService<TestServicesImp>();
            t1.Name = "张三";
            t1.SayHi();

            var t2 = sp.GetService<TestServicesImp>();
            t2.Name = "李四";
            t2.SayHi();

            var referenceEquals = object.ReferenceEquals(t1, t2);
            Console.WriteLine(referenceEquals);
        }
    }
}

运行结果!因为在瞬时生命周期中,每次获取服务都会创建新的实例。 因此通过object.ReferenceEquals方法比较了t1和t2是否是同一个实例,结果会输出false

🚀 Scoped

我们将上面代码中的服务注册AddTransient方法换成AddScoped,然后t2.SayHi();换成t1.SayHi();,再试一次。

    public static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddScoped<TestServicesImp>();
        using (ServiceProvider sp = serviceCollection.BuildServiceProvider())
        {
            var t1 = sp.GetService<TestServicesImp>();
            t1.Name = "张三";
            t1.SayHi();

            var t2 = sp.GetService<TestServicesImp>();
            t2.Name = "李四";
            t1.SayHi();

            var referenceEquals = object.ReferenceEquals(t1, t2);
            Console.WriteLine(referenceEquals);
        }
    }

发现这次的比较结果为true,并且第二次调用SayHi也是使用t1,但依然输出了李四,因此可以得出,两次获取服务得到的是同一个实例。

 👻我们对代码再进行改造一下,创建一个新的服务作用域,通过这个作用域的ServiceProvider对象获取了另一个TestServicesImp的实例t2。

    public static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddScoped<TestServicesImp>();
        using (ServiceProvider sp = serviceCollection.BuildServiceProvider())
        {
            var t1 = sp.GetService<TestServicesImp>();
            t1.Name = "张三";


            using (IServiceScope scope = sp.CreateScope())
            {
                var t2 = scope.ServiceProvider.GetService<TestServicesImp>();
                t2.Name = "李四";

                t1.SayHi();
                t2.SayHi();
                
                var referenceEquals = object.ReferenceEquals(t1, t2);
                Console.WriteLine(referenceEquals);
            }
        }
    }

因为它们是在不同的Scope中获取的,所以这次的结果是false

 

🚀Singleton 

我们将服务注册AddScoped方法,换成AddSingleton,然后再执行一次

    public static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddSingleton<TestServicesImp>();
        using (ServiceProvider sp = serviceCollection.BuildServiceProvider())
        {
            var t1 = sp.GetService<TestServicesImp>();
            t1.Name = "张三";


            using (IServiceScope scope = sp.CreateScope())
            {
                var t2 = scope.ServiceProvider.GetService<TestServicesImp>();
                t2.Name = "李四";

                t1.SayHi();
                t2.SayHi();
                
                var referenceEquals = object.ReferenceEquals(t1, t2);
                Console.WriteLine(referenceEquals);
            }
        }
    }

在输出结果中很显然可以看出使用AddSingleton注册服务,每次请求都返回同一个实例


http://www.niftyadmin.cn/n/5134270.html

相关文章

【每日一题】H 指数 II

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;二分查找 写在最后 Tag 【二分查找】【数组】【2023-10-30】 题目来源 275. H 指数 II 题目解读 本题与 274. H 指数 题目一致&#xff0c;只是加强了一下条件&#xff0c;数组是有序的。 解题思路 方法一&#xff…

C/C++角谷猜想 2020年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C角谷猜想 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C角谷猜想 2020年12月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 所谓角谷猜想&#xff0c;是指对于任意一个正整数&…

idea中Run/Debug Python项目报错 Argument for @NotNull parameter ‘module‘ of ...

idea中Run/Debug Python项目报错 Argument for NotNull parameter module of ... idea中运行Python项目main.py时报错&#xff1a; Error running main: Argument for NotNull parameter module of com/intellij/openapi/roots/ModuleRootManager.getInstance must not be nu…

Stable Diffusion系列(一):古早显卡上最新版 WebUI 安装及简单操作

文章目录 Stable Diffusion安装AnimateDiff插件适配sdxl模型适配 Stable Diffusion使用插件安装界面设置基础文生图加入lora的文生图 Stable Diffusion安装 我的情况比较特殊&#xff0c;显卡版本太老&#xff0c;最高也就支持cuda10.2&#xff0c;因此只能安装pytorch1.12.1&…

[Linux]线程池

[Linux]线程池 文章目录 [Linux]线程池线程池的概念线程池的优点线程池的应用场景线程池的实现 线程池的概念 线程池是一种线程使用模式。线程池是一种特殊的生产消费模型&#xff0c;用户作为生产者&#xff0c;线程池作为消费者和缓冲区。 线程过多会带来调度开销&#xff0c…

线段树 区间赋值 + 区间加减 + 求区间最值

线段树好题&#xff1a;P1253 扶苏的问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 区间赋值 区间加减 求区间最大。 对于区间赋值和区间加减来说&#xff0c;需要两个懒标记&#xff0c;一个表示赋值cover&#xff0c;一个表示加减add。 区间赋值的优先级大于区间加…

分类预测 | Matlab实现KOA-CNN-BiGRU-selfAttention多特征分类预测(自注意力机制)

分类预测 | Matlab实现KOA-CNN-BiGRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09; 目录 分类预测 | Matlab实现KOA-CNN-BiGRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09;分类效果基本描述程序设计参考资料 分类效果 基本描述 1.M…

动静分离技术

一、HAproxy 动静分离 1、概念&#xff1a; HAproxy 动静分离技术是一种用于优化 Web 服务器性能和提高用户体验的策略&#xff0c;它通过将动态内容和静态内容分别路由到不同的后端服务器来实现&#xff0c;减轻服务器负载&#xff0c;提高网站的响应速度。 动态内容包括由…