依赖注入(Dependency Injection,DI),简称DI,它可以降低各模块之间的耦合

首先需要安装两个Nuget包:

Microsoft.Extensions.DependencyInjection

Microsoft.Extensions.DependencyInjection.Abstractions

安装完之后要在主程序里面引用第一个包

using Microsoft.Extensions.DependencyInjection

提前准备好一个接口和两个实现类

public interface ITestService
{
public string Name { get; set; }
public void SayHi();
}
public class TestServiceImpl : ITestService
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine($"Hi, I'm {Name}");
}
}
    public class TestServiceImpl2 : ITestService
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine($"你好,我是{Name}");
}
}

然后在主程序中调用,以下是一个服务从注册到被使用的代码

//首先声明一个容器服务的对象,将其命名为services
//然后将需要被注册服务的对象TestServiceImpl添加放入容器服务对象services中
//添加方式有三种
//services.AddTransient
//services.AddSingleton
//services.AddScoped
//添加完服务之后使用services.BuildServiceProvider()方法构造出服务容器sp
//使用sp.GetService<TestServiceImpl>()即可使用刚刚添加进去的TestServiceImpl,如果没有对象被添加进服务,则是Null;
//sp.GetRequiredService,如果没有对象被添加进服务则会抛异常
//如果注册了多个服务,使用的是GetService,那么实际上选择的是最后一个服务(此处未体现) ServiceCollection services = new ServiceCollection();
//services.AddTransient<TestServiceImpl>();
//services.AddSingleton<TestServiceImpl>();
services.AddScoped<TestServiceImpl>();
using (ServiceProvider sp = services.BuildServiceProvider())
{
TestServiceImpl t1 = sp.GetService<TestServiceImpl>();
testService.Name = "tom";
testService.SayHi();
}

关于三种添加方式AddTransient(瞬态),AddSingleton(单例),AddScoped(范围);

使用AddTransient添加到服务的对象,每一次获取服务sp.GetService都是新的

而使用AddSingleton添加到服务的对象,每一次获取服务sp.GetService都是原来的

ServiceCollection services = new ServiceCollection();
services.AddTransient<TestServiceImpl>();
services.AddSingleton<TestServiceImpl2>();
using (ServiceProvider sp = services.BuildServiceProvider())
{
//使用AddTransient添加的
/*输出结果:
Hi, I'm xiaoli
False
Hi, I'm dali
Hi, I'm xiaoli
*/
TestServiceImpl t1 = sp.GetService<TestServiceImpl>();
t1.Name = "xiaoli";
t1.SayHi(); TestServiceImpl t2 = sp.GetService<TestServiceImpl>();
Console.WriteLine(object.ReferenceEquals(t1,t2));
t2.Name = "dali";
t2.SayHi();
t1.SayHi(); //使用AddSingleton添加的
/*输出结果:
你好,我是xiaoli
True
你好,我是dali
你好,我是dali*/
TestServiceImpl2 tt1 = sp.GetService<TestServiceImpl2>();
tt1.Name = "xiaoli";
tt1.SayHi(); TestServiceImpl2 tt2 = sp.GetService<TestServiceImpl2>();
Console.WriteLine(object.ReferenceEquals(tt1, tt2));
tt2.Name = "dali";
tt2.SayHi();
tt1.SayHi();
}

如果使用的是AddScoped,并且还限定了范围,那么在同一个范围内每次获取到的对象都是一样的

ServiceCollection services = new ServiceCollection();
services.AddScoped<TestServiceImpl>();
using (ServiceProvider sp = services.BuildServiceProvider())
{
TestServiceImpl tt1;
//在iss中获取Scope相关对象,iss1.ServiceProvider,而不是sp
using (IServiceScope iss1 = sp.CreateScope())
{
TestServiceImpl t1 = iss1.ServiceProvider.GetService<TestServiceImpl>();
t1.Name = "xiaoli";
t1.SayHi(); TestServiceImpl t2 = iss1.ServiceProvider.GetService<TestServiceImpl>();
Console.WriteLine(object.ReferenceEquals(t1, t2));
Console.WriteLine(t1.GetType());
tt1 = t1;
} using (IServiceScope iss2 = sp.CreateScope())
{
TestServiceImpl t1 = iss2.ServiceProvider.GetService<TestServiceImpl>();
t1.Name = "xiaoli";
t1.SayHi(); TestServiceImpl t2 = iss2.ServiceProvider.GetService<TestServiceImpl>(); //true 同一个范围内的对象相同
Console.WriteLine(object.ReferenceEquals(t1, t2)); //false,两个范围(scope)的对象不相同
Console.WriteLine(object.ReferenceEquals(tt1, t2));
}
} /*
Hi, I'm xiaoli
True
ioc1.TestServiceImpl
Hi, I'm xiaoli
True
False
*/

生命周期的选择:如果类无状态,建议为Singleton;如果类有状态,且有Scope控制,建议为Scoped,因为通常这种Scope控制下的代码都是运行在同一个线程中的,没有并发修改的问题;在使用Transient的时候要谨慎。

简单应用:

创建3个接口和对应的实现类,再建一个服务容器类

//日志信息
interface ILog
{
public void Log(string msg);
} class LogImpl : ILog
{
public void Log(string msg)
{
Console.WriteLine($"日志信息:{msg}");
}
} //配置信息
interface IConfig
{
public string GetValue(string name);
} class ConfigImpl : IConfig
{
public string GetValue(string name)
{
return "Hello";
}
} //保存信息
interface IStorage
{
public void Save(string content, string name);
}
class StorageImpl : IStorage
{
private readonly IConfig config;
public StorageImpl(IConfig config)
{
this.config = config;
}
public void Save(string content, string name)
{
string server = config.GetValue("server");
Console.WriteLine($"向服务器:{server}的文件名为:{name}上传{content}");
}
} //服务容器
class Controller
{
private readonly ILog log;
private readonly IStorage storage;
public Controller(ILog log, IStorage storage)
{
this.log = log;
this.storage = storage;
}
public void Test()
{
log.Log("开始上传");
storage.Save("4646461jhk", "1.txt");
log.Log("上传完毕");
}
}

在主函数中实现

static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
services.AddScoped<Controller>();
services.AddScoped<ILog, LogImpl>();
services.AddScoped<IStorage, StorageImpl>();
services.AddScoped<IConfig, ConfigImpl>(); using(ServiceProvider sp = services.BuildServiceProvider())
{
var c = sp.GetRequiredService<Controller>();
c.Test();
}
Console.ReadKey();
} /*输出结果
日志信息:开始上传
向服务器:Hello的文件名为:1.txt上传4646461jhk
日志信息:上传完毕
*/

学习来自杨中科大佬在某站上面的视频

.net core的依赖注入学习的更多相关文章

  1. ASP.NET Core之依赖注入

    本文翻译自:http://www.tutorialsteacher.com/core/dependency-injection-in-aspnet-core ASP.NET Core支持依赖注入,依赖 ...

  2. 【半小时大话.net依赖注入】(下)详解AutoFac+实战Mvc、Api以及.NET Core的依赖注入

    系列目录 上|理论基础+实战控制台程序实现AutoFac注入 下|详解AutoFac+实战Mvc.Api以及.NET Core的依赖注入 前言 本来计划是五篇文章的,每章发个半小时随便翻翻就能懂,但是 ...

  3. 几十行代码实现ASP.NET Core自动依赖注入

    在开发.NET Core web服务的时候,我们习惯使用自带的依赖注入容器来进行注入. 于是就会经常进行一个很频繁的的重复动作:定义一个接口->写实现类->注入 有时候会忘了写Add这一步 ...

  4. 重新整理 .net core 实践篇————依赖注入应用[二]

    前言 这里介绍一下.net core的依赖注入框架,其中其代码原理在我的另一个整理<<重新整理 1400篇>>中已经写了,故而专门整理应用这一块. 以下只是个人整理,如有问题, ...

  5. 【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类

    依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体原则就是:俺要啥,你就给俺送啥过来.服务类型的实例转由容器自动管理,无需我们在代码中显式处理. 因此,有了依 ...

  6. .Net Core 通过依赖注入和动态加载程序集实现宿程序和接口实现类库完全解构

    网上很多.Net Core依赖注入的例子代码,例如再宿主程序中要这样写: services.AddTransient<Interface1, Class1>(); 其中Interface1 ...

  7. .NET Core的依赖注入[1]: 控制反转

    写在前面:我之前写过一系列关于.NET Core依赖注入的文章,由于.NET Core依赖注入框架的实现原理发生了很大的改变,加上我对包括IoC和DI这些理论层面的东西又有了一些新的理解,所以我在此基 ...

  8. .NET Core 中依赖注入 AutoMapper 小记

    最近在 review 代码时发现同事没有像其他项目那样使用 AutoMapper.Mapper.Initialize() 静态方法配置映射,而是使用了依赖注入 IMapper 接口的方式 servic ...

  9. 用工厂模式解决ASP.NET Core中依赖注入的一个烦恼

    这是最近在实际开发中遇到的一个问题,用 asp.net core 开发一个后端 web api ,根据指定的 key 清除 2 台 memcached 服务器上的缓存.背景是我们在进行 .net co ...

  10. .Net Core 使用依赖注入

    ASP.NET Core 源码阅读笔记(1) ---Microsoft.Extensions.DependencyInjection 在asp .net中使用依赖注入很简单,只需要在Startup类的 ...

随机推荐

  1. K8S通过Yaml部署Nacos,注册服务报错503

    报错信息: ErrCode:503, ErrMsg:server is DOWN now .detailed error message: Optional[Distro protocol XXXX] ...

  2. 【实时渲染】3DCAT实时渲染云在BIM领域的应用

    很多人不知道实时渲染云在BIM领域都有哪些应用,今天3DCAT就为大家整理了一篇关于实时渲染云在BIM领域的应用介绍的文章.我们将会从什么是BIM.BIM在协作方面的挑战.3DCAT的解决方案及3DC ...

  3. 记录--20行js就能实现逐字显示效果???-打字机效果

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 效果演示 横版 竖版 思路分析 可以看到文字是一段一段的并且独占一行,使用段落标签p表示一行 一段文字内,字是一个一个显示的,所以这里每一 ...

  4. Redis源码学习(1)──字符串

    redis 版本:5.0 本文代码在Redis源码中的位置:redis/src/sds.c.redis/src/sds.h 源码整体结构 src:核心实现代码,用 C 语言编写 tests:单元测试代 ...

  5. Python - inspect 模块的简单使用

    Python中的inspect模块解析 Python的inspect模块是一个强大的内省工具,允许开发者检查(inspect)活动对象和源代码.它提供了一系列函数,用于获取信息关于正在运行的程序和调用 ...

  6. AABO:自适应Anchor设置优化,性能榨取的最后一步 | ECCV 2020 Spotlight

    论文提出超参数优化方法AABO,该方法核心基于贝叶斯优化和Sub-Sample方法,能够自适应的搜索最优的anchor设置.从实验结果来看,AABO能够仅通过anchor设置优化,为SOTA目标检测方 ...

  7. Windows下获取设备管理器列表信息-setupAPI

    背景及问题: 在与硬件打交道时,经常需要知道当前设备连接的硬件信息,以便连接正确的硬件,比如串口通讯查询连接的硬件及端口,一般手工的方式就是去设备管理器查看相应的信息,应用程序如何读取这一部分信息呢, ...

  8. #线段树,模拟费用流#CF280D k-Maximum Subsequence Sum

    题目 给定一个大小为 \(n\) 的序列,要求支持单点修改和查询区间内至多 \(k\) 个不交子区间之和的最大值(可以不取) 分析 考虑源点向每个点.每个点向汇点流流量1费用0的边,每个点向右边的点流 ...

  9. 使用OHOS SDK构建zlib

    参照OHOS IDE和SDK的安装方法配置好开发环境. 从gitee下载源码,当前最新的提交记录ID为04f42ceca40f73e2978b50e93806c2a18c1281fc. 执行如下命令: ...

  10. 开发板如何适配OpenHarmony 3.2

      简介 OpenAtom OpenHarmony(以下简称"OpenHarmony") 3.2 Beta5版本在OpenHarmony 3.1 Release版本的基础上,有以下 ...