首页 > 其他分享 >【WPF依赖注入】开篇. NET Core 控制反转(IoC)和依赖注入(DI) IServiceCollection

【WPF依赖注入】开篇. NET Core 控制反转(IoC)和依赖注入(DI) IServiceCollection

时间:2022-10-31 22:11:52浏览次数:88  
标签:Core 依赖 AddSingleton DI ClassB IServiceCollection new public 注入

参考

Microsoft.Extensions.DependencyInjection入门

https://www.cnblogs.com/zcqiand/p/14257661.html

原文:NET Core 依赖注入的 IServiceCollection

 

前置阅读

在阅读本文章之前,你可以先阅读:

  • 什么是依赖注入

简介

Microsoft.Extensions.DependencyInjection是.NET Core内置依赖注入模块。

.NET Core 依赖注入的 IServiceCollection

        什么是依赖注入(DI)和DI容器?
        注册服务
        服务生命周期
        我们注册服务时会发生什么?
        实例注册

    .NET Core内置依赖项注入容器 Microsoft.Extensions.DependencyInjection

什么是依赖注入(DI)和DI容器? 

   Microsoft依赖项注入容器只是一组类,它们组合到一个代码库中,这个库会自动创建并管理程序中需要的对象

public class ClassA
{
    public void DoWork() 
    {
        var b = new ClassB();
        b.DoStuff();
    }
}

public class ClassB
{
    public void DoStuff()
    {
        // ...
    }
}

    ClassA 直接依赖ClassB,并且在它的 DoWork() 方法中,new了一个ClassB,然后调用了ClassB的 DoStuff()方法
 首先,加一个构造函数,并且指定了ClassA依赖的类型,调用构造函数时,必须提供ClassB的实例, 在ClassA的内部,我们不会去new一个ClassB,ClassB完全是由外部传入的,这里就是控制反转(IOC)

public class ClassA
{
    private readonly ClassB _dependency;

    public ClassA(ClassB classB) => _dependency = classB;

    public void DoWork() => _dependency.DoStuff();
}

public class ClassB : IThing
{
    public void DoStuff()
    {
        // ...
    }
}

加一个接口IThing,现在,我们已经应用了SOLID的依赖倒置原则,我们不再依赖具体的实现,相反,我们依赖于IThing抽象,在构造函数中,只需要传入IThing的实现就好了

public interface IThing
{
    public void DoStuff();
}

public class ClassA
{
    private readonly IThing _dependency;

    public ClassA(IThing thing) => _dependency = thing;

    public void DoWork() => _dependency.DoStuff();
}

public class ClassB : IThing
{
    public void DoStuff()
    {
        // ...
    }
}

手动new了一个ClassB,它实现了IThing接口,然后创建ClassA的时候,直接把thing传入构造函数中

class Program
{
    static void Main(string[] args)
    {
        IThing thing = new ClassB();
        ClassA classA = new ClassA(thing);
        classA.DoWork();
    }
}
  • 在实际中呢,我们代码中有很多类型,然后有各种各样的依赖关系
  • 这个时候我们就需要一个DI容器,我们对容器进行配置,然它知道什么类型,然后负责自动创建并管理对象 (通常称为服务)

注册服务


  通常, Microsoft DI 容器需要在Startup类中配置,在这里,您可以使用ConfigureServices方法向容器注册服务,在应用程序托管生命周期的早期,将调用ConfigureServices方法,它有一个参数`IServiceCollection``,这个参数在初始化应用程序时传入

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 注册服务
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    }
}
  • 为了尽可能的简单,我们也可以在控制台中使用 Microsoft DependencyInjection

  • 创建控制台程序后,我们首先在项目中引入 Microsoft.Extensions.DependencyInjection

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
  </ItemGroup>

</Project>

现在我们开始注册我们的服务,但是我们需要一个IServiceCollection,让我们看一下IServiceCollection的定义

public interface IServiceCollection : IList<ServiceDescriptor>
{
}
  • IServiceCollection没有定义其任何成员,而是从IList<ServiceDescriptor>派生
  • Microsoft.Extensions.DepenencyInjection程序包里面,它有一个默认的实现:ServiceCollection
public class ServiceCollection : IServiceCollection
{
    private readonly List<ServiceDescriptor> _descriptors = new List<ServiceDescriptor>();

    public int Count => _descriptors.Count;

    public bool IsReadOnly => false;

    public ServiceDescriptor this[int index]
    {
        get
        {
            return _descriptors[index];
        }
        set
        {
            _descriptors[index] = value;
        }
    }

    // ...
}
  • 它有一个私有的List集合:_descriptors,里面是ServiceDescriptor

  • 让我们从创建一个ServiceCollection,然后注册两个服务

static void Main(string[] args)
{
    var serviceCollection = new ServiceCollection();

    serviceCollection.AddSingleton<ClassA>();
    serviceCollection.AddSingleton<IThing, ClassB>();

    Console.WriteLine("Done");
}

在前面的代码中,我们已经使用AddSingleton方法注册了两个服务,这不是IServiceCollection接口定义的方法,也不在ServiceCollection上,这是IServiceCollection的扩展方法,这个方法在ServiceCollectionServiceExtensions的扩展类中,接下来,我会介绍这个方法是如何注册服务的,不过这之前,我们首先回顾下服务生命周期的概念

服务生命周期

  在Microsoft依赖项注入框架中,我们可以使用三种生命周期注册服务,分别是单例(Singleton)、瞬时(Transient)、作用域(Scoped),在上面的代码中,使用了AddSingleton()来注册服务。
  使用Singleton服务的优点是我们不会创建多个服务实例,只会创建一个实例,保存到DI容器中,直到程序退出,这不仅效率高,而且性能高,但是有一个要注意的点,如果在多线程中使用了Singleton,要考虑线程安全的问题,保证它不会有冲突
    瞬时(Transient)和单例(Singleton)模式是相反的,每次使用时,DI容器都是创建一个新的实例。
    作用域(Scoped),在一个作用域内,会使用同一个实例,像EF Core的DbContext上下文就被注册为作用域服务。

我们注册服务时会发生什么?

  • 在上面的代码中,已经注册了两个单例服务
serviceCollection.AddSingleton<ClassA>();
serviceCollection.AddSingleton<IThing, ClassB>();

这是最终的AddSingleton方法:

public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, Type implementationType)
{
    if (services == null)
    {
        throw new ArgumentNullException(nameof(services));
    }
    if (serviceType == null)
    {
        throw new ArgumentNullException(nameof(serviceType));
    }
    if (implementationType == null)
    {
        throw new ArgumentNullException(nameof(implementationType));
    }
    return Add(services, serviceType, implementationType, ServiceLifetime.Singleton);
}
  • 我们可以看到AddSingleton方法调用了私有的Add()方法,并且传入了一个生命周期的枚举值ServiceLifetime.Singleton

  • 让我们看一下Add方法的工作原理:

private static IServiceCollection Add(IServiceCollection collection, Type serviceType, Type implementationType, ServiceLifetime lifetime)
{
    var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
    collection.Add(descriptor);
    
    return collection;
}

它创建一个新的ServiceDescriptor实例,传入服务类型,实现类型(可能与服务类型相同)和生命周期,然后调用Add方法添加到列表中
之前,我们了解到IServiceCollection本质上是包装了List <ServiceDescriptor>, ServiceDescriptor类很简单,代表一个注册的服务,包括其服务类型,实现类型和生命周期

实例注册

我们也可以手动new一个实例,然后传入到AddSingleton()方法中:

var myInstance = new ClassB();
serviceCollection.AddSingleton<IThing>(myInstance);
  • 使用 ServiceDescriptor
  • 我们还可以手动定义一个ServiceDescriptor,然后直接添加到IServiceCollection中
var descriptor = new ServiceDescriptor(typeof(IThing), typeof(ClassB), ServiceLifetime.Singleton);
serviceCollection.Add(descriptor);

.NET中的DI的一些核心知识,可以直接创建ServiceCollection来使用Microsoft DI框架,了解了IServiceCollection上的AddSingleton扩展方法是如何工作,以及它们最终创建了一个ServiceDescriptor,然后添加到一个ServiceCollection包装的List集合中
————————————————
版权声明:本文为CSDN博主「黑夜中的潜行者」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43562262/article/details/114438889

 

标签:Core,依赖,AddSingleton,DI,ClassB,IServiceCollection,new,public,注入
From: https://www.cnblogs.com/cdaniu/p/16845894.html

相关文章

  • C# net core 从文件流中获取文件头、匹配文件类型
    常用文件的文件头如下:(以前六位为准)JPEG(jpg),文件头:FFD8FFPNG(png),文件头:89504E47GIF(gif),文件头:47494638TIFF(tif),文件头:49492A00WindowsBitmap(bmp),文件头:4......
  • 模板注入--Spring boot Thymeleaf 模板注入
    Thymeleaf模板安全分析1、Thymeleaf简介Thymeleaf是用于Web和独立环境的现代服务器端Java模板引擎。类似与pythonweb开发中的jinja模板引擎。顺便说一句,Thymeleaf是spr......
  • 工厂注入异常
    工厂注入的异常,真是令人蛋疼,仿照构造方法和属性的注入方法,我去注入就因为:————————怪我了,让你找不到进入factory的大门,哎,,,,,!下次注意,马上就该秋招,就这粗心的程度,令人忧......
  • 二、.Net Core搭建Ocelot
    Ocelot是系统中对外暴露的一个请求入口,所有外部接口都必须通过这个网关才能向下游API发出请求1、Nuget引用Ocelot(注意版本,我用的是16.0.1)2、根目录添加配置文件Ocelot.js......
  • Solr 8.11入门教程(2)创建core
    新建core添加core命令添加使用命令比较简单~$bin/solrcreate-cmytest[core名称]这样就添加完了。CoreAdmin就可以看到了。手动添加手动添加相对复杂一些,需要提......
  • cuda cores
    基本介绍从这个link看的:https://www.techcenturion.com/nvidia-cuda-cores/其中,抽象上这里表述较好理解:LetusconsideranexampletounderstandtheworkingofCUDA......
  • Solr 8.11入门教程(2)创建core
    新建core添加core命令添加使用命令比较简单~$bin/solrcreate-cmytest[core名称]这样就添加完了。CoreAdmin就可以看到了。手动添加手动添加相对复杂一些,需要提前创建目......
  • Vue privide 和inject 依赖注入的用法
    from表示在可用的注入内容中搜索用的key,default当然就是默认值。 这里就是我们说的provide,向下提供信息,这里提供的是当前的vue实例,相当于给了后代一个接口。这样在任......
  • Solr 8.11入门教程(2)新建core
    Solr8.11入门教程(2)新建core添加core命令添加使用命令比较简单~$bin/solrcreate-cmytest[core名称]这样就添加完了。CoreAdmin就可以看到了。手动添加手动......
  • Vue项目npm install下载依赖,报错:npm install 报错(npm ERR! errno -4048...(已解决✔)
    vue项目下载依赖npminstall报错:(npmERR!errno-4048,Error:EPERM:operationnotpermitted,)解决方法出现这种报错的时候有我用了清空缓存的方法:1,清理本地缓存:cach......