依赖注入(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. nginx部署SSL证书后,使用域名访问报错-net::ERR_SSL_PROTOCOL_ERROR

    一.问题由来 最近在做一个小程序的后台,自己去微信官网上查看了相关的规定,小程序正式发布时,要求比较严格,必须是使用https+域名访问,自己在 阿里云购买了一个域名,可是没有备案.SSL证书去阿里云 ...

  2. IDEA无限试用插件

    原文地址 之前一直在找激活方法,忽然想到IDEA不是可以试用吗?一直试用不就可以变相地达到了激活的效果? 本篇作废,本篇作废,本篇作废,由于IDEA插件的问题,导致并不能成功的进行重置试用 新整了个J ...

  3. 模板函数中的const

    所有讨论都是底层const指针或引用,顶层const不会传递进模板. 模板中有const,不管传进来是否是const,T都是非const类型. template<typename T> v ...

  4. 实时3D渲染它是如何工作的?可以在哪些行业应用?

    随着新兴技术--3D渲染的发展,交互应用的质量有了极大的提高.用实时三维渲染软件创建的沉浸式数字体验,几乎与现实没有区别了.随着技术的逐步改进,在价格较低的个人工作站上渲染3D图像变得更加容易,设计师 ...

  5. django(web框架推导、简介、数据库初识)

    一 web框架推导 1 软件开发架构 cs架构bs架构bs本质是也是cs # HTTP协议:无状态,无连接,基于请求,基于tcp/ip的应用层协议 # mysql:c/s架构,底层基于soket,自己 ...

  6. 记录--Vue3基于Grid布局简单实现一个瀑布流组件

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 在学习Grid布局之时,我发现其是CSS中的一种强大的布局方案,它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局 ...

  7. .NET开源免费、功能强大的 Windows 截图录屏神器

    前言 今天大姚给大家分享一款.NET开源免费(基于GPL3.0开源协议).功能强大.简洁灵活的 Windows 截图.录屏.Gif动图制作神器:ShareX. 功能特性 ShareX 是一个开源的屏幕 ...

  8. 基于logisim-D触发器设计四人抢答电路

    实验1:设计一个简易4人知识竞赛抢答电路,要求是: 裁判掌握一个按钮,作用是给电路复位和发出抢答开始命令;4名竞赛者各掌握一个按钮,每人对应一个指示灯,在主持人发出开始抢答命令后,哪位参赛者先按钮其对 ...

  9. RepPointsV2:更多的监督任务,更强的性能 | NIPS 2020

    RepPointsV2的整体思想类似与Mask R-CNN,加入更多的任务来监督目标检测算法的学习.虽然在创新性上可能不够新颖,但论文的通用性还是很不错的,而且将角点任务的输出用于联合推理,从对比实验 ...

  10. KingbaseES 的oracle兼容性参数

    KingbaseES用户可通过设置相关的数据库兼容参数,部分或全部启用Oracle兼容特性. 常用的兼容性参数有以下这些: 参数名称 参数说明 ora_forbid_func_polymorphism ...