【 .NET Core 3.0 】框架之九 || 依赖注入 与 IoC

本文有配套视频:https://www.bilibili.com/video/av58096866/?p=5

 前言

 

1、重要:如果你实现了解耦,也就是 api 层只引用了 IService 和 IRepository 的话,那每次修改 service 层,都需要清理解决方案,重新编译项目,因为这个时候你的api层的dll,还是之前未修改的代码。

 

2、重要+ :请注意,依赖注入的目的不是为了解耦,依赖注入是为了控制反转,通俗来说,就是不用我们自己去 new 服务实例了,所以大家不需要一定去解耦(比如下文说到的我没有引用 Service层 和 Repository层),我下一个DDD系列,依赖注入就没有解耦,因为我用的是自带的注入,不是Autofac的反射dll ,我解耦的目的,是为了让大家更好的理解,服务是怎么注入到宿主容器里的。

 

说接上文,上回说到了《八 || API项目整体搭建 6.3 异步泛型+依赖注入初探》,后来的标题中,我把仓储两个字给去掉了,因为好像大家对这个模式很有不同的看法,嗯~可能还是我学艺不精,没有说到其中的好处,现在在学DDD领域驱动设计相关资料,有了好的灵感再给大家分享吧。

  虽然项目整体可以运行了,但是我还有几个小知识点要说下,主要是1、依赖注入和AOP相关知识;2、跨域代理等问题(因为Vue是基于Node开发的,与后台API接口不在同一个地址);3、实体类的DTO相关小问题;4、Redis缓存等;5、部署服务器中的各种坑;虽然都是很小的知识点,我还是都下给大家说下的,好啦,开始今天的讲解;

零、今天完成的绿色部分

 640?wx_fmt=png

 

一、依赖注入的理解和思考

 

更新(19-04-17):如果想好好的理解依赖注入,可以从以下几个方面入手:

1、项目之间引用是如何起作用的,比如为啥 api 层只是引用了 service 层,那为啥也能使用 repository 和 model 等多层的类?

2、项目在启动的时候,也就是运行时,是如何动态 获取和访问 每一个对象的实例的?也就是 new 的原理

3、项目中有 n 个类,对应 m 个实例等,那这些服务,都放在了哪里?肯定每一个项目都有专属自己的一块。如果项目不启动的话,内存里肯定是没有这些服务的。

4、使用接口(面向抽象)的好处?

5、在项目后期,如何业务需要要全部修改接口的实现类,比如想把 IA = new A();全部  改成 IA = new B();

6、反射的重要性,为什么要用到反射 dll ?

如果这些每一条自己都能说清楚,那肯定就知道依赖注入是干啥的了。

 

说到依赖,我就想到了网上有一个例子,依赖注入和工厂模式中的相似和不同:

(1)原始社会里,没有社会分工。须要斧子的人(调用者)仅仅能自己去磨一把斧子(被调用者)。相应的情形为:软件程序里的调用者自己创建被调用者。(2)进入工业社会,工厂出现。斧子不再由普通人完毕,而在工厂里被生产出来,此时须要斧子的人(调用者)找到工厂,购买斧子,无须关心斧子的制造过程。相应软件程序的简单工厂的设计模式。(3)进入“按需分配”社会,需要斧子的人不需要找到工厂,我们只需要去干活就行,斧子已经给我们自动准备好了,直接用就可以了。

 

640?wx_fmt=png

 

首先,我们需要了解下什么是控制反转IOC,举个栗子,我在之前开发简单商城的时候,其中呢,订单模块,有订单表,那里边肯定有订单详情表,而且呢订单详情表中还有商品信息表,商品信息表还关联了价格规格表,或者其他的物流信息,商家信息,当然,我们可以放到一个大表里,可是你一定不会这么做,因为太庞大,所以必定分表,那必定会出现类中套类的局面,这就是依赖,比如上边的,订单表就依赖了详情表,我们在实例化订单实体类的时候,也需要手动实例详情表,当然,EF框架中,会自动生成。不过倘若有一个程序员把详情表实体类改错了,那订单表就崩溃了,哦不!我是遇到过这样的情景。

640?wx_fmt=png

 

怎么解决这个问题呢,就出现了控制反转。网上看到一个挺好的讲解:

1、没有引入IOC之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,A直接使用new关键字创建B的实例,程序高度耦合,效率低下,无论是创建还是使用B对象,控制权都在自己手上。

2、软件系统在引入IOC容器之后,这种情形就完全改变了,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。

3、依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。依赖注入通常有两种:

这个就是依赖注入的方式。


什么是控制反转(IoC)


Inversion of Control,英文缩写为IoC,不是什么技术,而是一种设计思想。

   

简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。IOC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦,如下图:

640?wx_fmt=png

 

大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“黏合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“黏合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“黏合剂”的由来。

我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:

640?wx_fmt=png

 

    我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,这将是一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系!

在上面文章中,我们已经了解到了,什么是依赖倒置、控制反转(IOC),什么是依赖注入(DI),网上这个有很多很多的讲解,我这里就不说明了,其实主要是见到这样的,就是存在依赖

public class A : D	
{	public A(B b)	{	// do something   	}	C c = new C();	
}

 

就比如我们的项目中的BlogController,只要是通过new 实例化的,都是存在依赖

 

使用依赖注入呢,有以下优点:

  • 传统的代码,每个对象负责管理与自己需要依赖的对象,导致如果需要切换依赖对象的实现类时,需要修改多处地方。同时,过度耦合也使得对象难以进行单元测试。

  • 依赖注入把对象的创造交给外部去管理,很好的解决了代码紧耦合(tight couple)的问题,是一种让代码实现松耦合(loose couple)的机制。

  • 松耦合让代码更具灵活性,能更好地应对需求变动,以及方便单元测试。

举个栗子,就是关于日志记录的

日志记录:有时需要调试分析,需要记录日志信息,这时可以采用输出到控制台、文件、数据库、远程服务器等;假设最初采用输出到控制台,直接在程序中实例化ILogger logger = new ConsoleLogger(),但有时又需要输出到别的文件中,也许关闭日志输出,就需要更改程序,把ConsoleLogger改成FileLogger或者NoLogger, new FileLogger()或者new SqlLogger() ,此时不断的更改代码,就显得心里不好了,如果采用依赖注入,就显得特别舒畅。

二、常见的IoC框架有哪些

1、Autofac+原生

我常用的还是原生注入和 Autofac 注入。

Autofac:貌似目前net下用的最多吧Ninject:目前好像没多少人用了Unity:也是较为常见

微软 core 自带的 DI

其实.Net Core 有自己的轻量级的IoC框架,

ASP.NET Core本身已经集成了一个轻量级的IOC容器,开发者只需要定义好接口后,在Startup.cs的ConfigureServices方法里使用对应生

命周期的绑定方法即可,常见方法如下

services.AddTransient<IApplicationService,ApplicationService>//服务在每次请求时被创建,它最好被用于轻量级无状态服务(如我们的Repository和ApplicationService服务)

services.AddScoped<IApplicationService,ApplicationService>//服务在每次请求时被创建,生命周期横贯整次请求

services.AddSingleton<IApplicationService,ApplicationService>//Singleton(单例) 服务在第一次请求时被创建(或者当我们在ConfigureServices中指定创建某一实例并运行方法),其后的每次请求将沿用已创建服务。如果开发者的应用需要单例服务情景,请设计成允许服务容器来对服务生命周期进行操作,而不是手动实现单例设计模式然后由开发者在自定义类中进行操作。

 当然.Net Core自身的容器还是比较简单,如果想要更多的功能和扩展,还是需要使用上边上个框架。

 

2、三种注入的生命周期 

权重:

AddSingleton→AddTransient→AddScoped

AddSingleton的生命周期:

项目启动-项目关闭   相当于静态类  只会有一个  

AddScoped的生命周期:

请求开始-请求结束  在这次请求中获取的对象都是同一个 

AddTransient的生命周期:

请求获取-(GC回收-主动释放) 每一次获取的对象都不是同一个

 

这里来个简单的小DEMO:

1、定义四个接口,并分别对其各自接口实现,目的是测试Singleton,Scope,Transient三种,以及最后的 Service 服务:

 public interface ISingTest	{	int Age { get; set; }	string Name { get; set; }	}	public class SingTest: ISingTest	{	public int Age { get; set; }	public string Name { get; set; }	}	//--------------------------	public interface ISconTest	{	int Age { get; set; }	string Name { get; set; }	}	public class SconTest: ISconTest	{	public int Age { get; set; }	public string Name { get; set; }	}	//--------------------------	public interface ITranTest	{	int Age { get; set; }	string Name { get; set; }	}	public class TranTest: ITranTest	{	public int Age { get; set; }	public string Name { get; set; }	}	//-----------------------	
public interface IAService	
{	void RedisTest();	
}	public class AService : IAService	{	private ISingTest sing; ITranTest tran; ISconTest scon;	public AService(ISingTest sing, ITranTest tran, ISconTest scon)	{	this.sing = sing;	this.tran = tran;	this.scon = scon;	}	public void RedisTest()	{	}	}

 

2、项目注入

640?wx_fmt=png

 

 

3、控制器调用

 

4、开始测试,三种注入方法出现的情况 

请求SetTest // GET api/values

 

640?wx_fmt=png

640?wx_fmt=png

AddSingleton的对象没有变

AddScoped的对象没有变化

AddTransient的对象发生变化

------------------------------------------------------------

请求 // GET api/values/5

640?wx_fmt=png

 

AddSingleton的对象没有变

AddScoped的对象发生变化

AddTransient的对象发生变化

 

注意:

由于AddScoped对象是在请求的时候创建的

所以不能在AddSingleton对象中使用

甚至也不能在AddTransient对象中使用

 

所以权重为

AddSingleton→AddTransient→AddScoped

 

不然则会抛如下异常

640?wx_fmt=png

 

三、较好用的IoC框架使用——Autofac

首先呢,我们要明白,我们注入是要注入到哪里——Controller API层。然后呢,我们看到了在接口调用的时候,如果需要其中的方法,需要using两个命名空间

 

接下来我们就需要做处理:

 

1、引入nuget包

在Nuget中引入两个Autofac.Extras.DynamicProxy(Autofac的动态代理,它依赖Autofac,所以可以不用单独引入Autofac)、Autofac.Extensions.DependencyInjection(Autofac的扩展),注意是最新版本的。

 <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="5.0.0" />	<PackageReference Include="Autofac.Extras.DynamicProxy" Version="4.5.0" />

 

640?wx_fmt=png

 

2、配置容器,注入服务

在startup.cs 文件中,增加一个方法,用来配置Autofac 服务容器

首先我们创建一个接口和对应的实现类:

 public interface IAdvertisementServices	{	int Test();	}	public class AdvertisementServices : IAdvertisementServices	{	public int Test()	{	return 1;	}	}	

然后将这个服务,注入到Autofac 容器里:

 public void ConfigureContainer(ContainerBuilder builder)	{	var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;	//直接注册某一个类和接口	//左边的是实现类,右边的As是接口	builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();	//注册要通过反射创建的组件	var servicesDllFile = Path.Combine(basePath, "Blog.Core.Services.dll");	var assemblysServices = Assembly.LoadFrom(servicesDllFile);	builder.RegisterAssemblyTypes(assemblysServices)	.AsImplementedInterfaces()	.InstancePerLifetimeScope()	.EnableInterfaceInterceptors();	}	

 

640?wx_fmt=png

这个时候我们就把 AdvertisementServices的new 实例化过程注入到了Autofac容器中,

这个时候要看明白,前边的是实现类,后边的是接口,顺序不要搞混了。

 

3、使用服务工厂,将Autofac容器添加到Host

为什么要这么做呢,从上边你也应该看到了,我们现在仅仅是配置了服务和容器,还没有添加到我们的项目宿主里,那我们的controller就拿不到相应的服务。

我们需要在 Program.cs 文件中,配置 UseServiceProviderFactory

public static IHostBuilder CreateHostBuilder(string[] args) =>	Host.CreateDefaultBuilder(args)	.UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS	.ConfigureWebHostDefaults(webBuilder =>	{	webBuilder.UseStartup<Startup>();	});	

 

4、使用构造函数方式来注入

依赖注入有三种方式(构造函数注入、属性注入和方式注入),我们平时基本都是使用其中的构造函数方式实现注入,

大家还记得默认控制器 WeatherForecastController 么,当时我们说到了,已经有了一个依赖注入的用法,就是 ILogger,那现在我们继续注入,

 

 

5、效果调试,已经成功

然后运行调试,发现在断点刚进入的时候,接口已经被实例化了,达到了注入的目的。

640?wx_fmt=png

 

注意:这里经常会遇到一个错误:None of the constructors found with ........,

查看你的service服务,是不是用了其他的仓储repository,但是又缺少了构造函数。

 

 

如果没有问题,大家就需要想想,除了 Autofac 还有没有其他的不用第三方框架的注入方法呢?聪明如你,netcore 还真自带了注入扩展。

 

6、NetCore 自带的注入实现效果

当然,我们用 Asp.net core 自带的注入方式也是可以的,也挺简单的,这里先说下使用方法:

640?wx_fmt=png

 

这个时候,我们发现已经成功的注入了,而且特别简单,那为啥还要使用 Autofac 这种第三方扩展呢,我们想一想,上边我们仅仅是注入了一个 Service ,但是项目中有那么多的类,都要一个个手动添加么,多累啊,答案当然不是滴~

 

 

四、整个 dll 程序集的注入

1、服务程序集注入方式 —— 未解耦

通过反射将 Blog.Core.Services 和 Blog.Core.Repository 两个程序集的全部方法注入

修改如下代码,注意这个时候需要在项目依赖中,右键,添加引用 Blog.Core.Services 层和 Repository 层 到项目中,如下图,这个时候我们的程序依赖了具体的服务

640?wx_fmt=png

 

核心代码如下,注意这里是 Load 模式(程序集名),还是在startup.cs 文件中,配置Autofac容器。

 

其他不变,运行项目,一切正常,换其他接口也可以,具体的就不细说。

到这里,Autofac依赖注入已经完成,基本的操作就是这样,不过可能你还没有真正体会到注入的好处,挑战下吧,看看下边的内容,将层级进行解耦试试!

 

 


 

2、程序集注入 —— 实现层级解耦

 

这是一个学习的思路,大家要多想想,可能会感觉无聊或者没用,但是对理解项目启动和加载,还是很有必要的。

1、项目最终只依赖抽象

最终的效果是这样的:工程只依赖抽象,把两个实现层删掉,引用这两个接口层。

640?wx_fmt=png

 

 

2、配置仓储和服务层的程序集输出

将 Blog.Repository 层和 Service 层项目生成地址改成相对路径,这样大家就不用手动拷贝这两个 dll 了,F6编译的时候就直接生成到了 api 层 bin 下了:

“...\Blog.Core\bin\Debug\”

640?wx_fmt=png

 

 

3、使用 LoadFile 加载服务层的程序集

 

这个时候,可能我们编译成功后,页面能正常启动,证明我们已经把 Service 和 Repository 两个服务层的所有服务给注册上了,但是访问某一个接口,还是会出现错误:

 640?wx_fmt=png

 

这个错误表示,我们的 SqlSugar 服务,没有被注册成功,那肯定就是我们的 Sqlsugar 程序集没有正常的引用,怎么办呢,直接在 api 层引用下就行。

 

640?wx_fmt=png

 

 

 

4、解除Service层和Repository层之间的耦合

还记得Blog.Core.Services中的BaseServices.cs么,它还是通过new 实例化的方式在创建,仿照contrller,修改BaseServices并在全部子类的构造函数中注入:

 public class BaseServices<TEntity> : IBaseServices<TEntity> where TEntity : class, new()	{	//public IBaseRepository<TEntity> baseDal = new BaseRepository<TEntity>();	public IBaseRepository<TEntity> baseDal;//通过在子类的构造函数中注入,这里是基类,不用构造函数	//...	}	public class AdvertisementServices : BaseServices<Advertisement>, IAdvertisementServices	{	IAdvertisementRepository dal;	public AdvertisementServices(IAdvertisementRepository dal)	{	this.dal = dal;	base.baseDal = dal;	}	}

 640?wx_fmt=png

 

好啦,现在整个项目已经完成了相互直接解耦的功能,以后就算是Repository和Service如何变化,接口层都不用修改,因为已经完成了注入,第三方Autofac会做实例化的过程。

 

5、容器内查看注入的服务数据

如果你想看看是否注入到容器里成功了,可以直接看看容器 ApplicationContainer 的内容:

640?wx_fmt=png

 

 

五、 无接口项目注入

1、接口形式的注入

上边我们讨论了很多,但是都是接口框架的,

比如:Service.dll 和与之对应的 IService.dll,Repository.dll和与之对应的 IRepository.dll,

这样,我们在多层之间使用服务的话,直接将我们需要使用的 new 对象,注入到容器里,然后我们就可以使用相应的接口了,

比如:我们想在 controller 里使用AdvertisementServices 类,那我们就可以直接使用它的接口 IAdvertisementServices,这样就很好的达到了解耦的目的,这样我们就可以在API层,就轻松的把 Service.dll 给解耦了;

如果我们需要在 Service类里,使用 AdvertisementRepository ,我们就直接使用对应的接口 IAdvertisementRepository,这样,我们就从 Service 层中,把仓储层给解耦了。

 

640?wx_fmt=png

 

2、如果没有接口

案例是这样的:

 如果我们的项目是这样的,没有接口,会怎么办:640?wx_fmt=png

 

这样的话,我们就不能使用上边的接口注入模式了,因为我们上边是把注入的服务,对应注册给了接口了 .AsImplementedInterfaces() ,我们就无法实现解耦了,因为根本没有了接口层,所以我们只能引用实现类层,这样注入:

640?wx_fmt=png

 

 

通过 builder.RegisterAssemblyTypes(assemblysRepository); 方法直接注入服务,没有其他的东西。

 

3、如果是没有接口的单独实体类

 

 

六、同一接口多实现类注入

这里暂时没有实例代码,如果你正好需要,可以看看这个博友的栗子:https://www.cnblogs.com/fuyujian/p/4115474.html

我会在之后的时间写个栗子放到这里。

 

 

 

七、CODE

https://github.com/anjoy8/Blog.Core

https://gitee.com/laozhangIsPhi/Blog.Core

 

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313422.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10月数据库排行:Microsoft SQL Server分数增加最多

DB-Engines 数据库流行度排行榜 10 月更新已发布&#xff0c;排名前二十如下&#xff1a;这期的数据比较有意思&#xff0c;到了这个月&#xff0c;Microsoft SQL Server 马上扭转局势&#xff0c;成了分数增长最多的一个&#xff0c;与上个月相比其增加了 9.66 分&#xff0c;…

VS Code 1.39 发布!Web 版 VS Code 是否离我们越来越近了?(文末彩蛋)

今天&#xff08;北京时间 2019 年 10 月 10 日&#xff09;&#xff0c;微软发布了 Visual Studio Code 1.39 版本。此版本主要更新的内容包括&#xff1a;Source Control tree view - 可以通过列表或者树状图两种方式来展示被改变的文件。Toggle region folding keyboard sho…

二叉树分析(两点最大距离)

转载自&#xff1a;http://blog.csdn.net/lalor/article/details/7626678 http://blog.csdn.net/lalor/article/details/7618120 把二叉树看成一个图&#xff0c;父子节点之间的连线看成是双向的&#xff0c;我们姑且定义"距离"为两节点之间边的个数。写…

IT从业的迷思与破解之道(更新)

我只是单纯做技术的程序员&#xff0c;什么靠微信广告攒钱这些&#xff0c;跟我没有半毛钱关系&#xff0c;初衷很简单&#xff0c;只重视正三观的正确技术知识分享在这到处都是线上培训&#xff0c;付费知识的社群里&#xff0c;随便搜个词都有您想要的内容哪轮到我们。技术的…

graphcut 用于最优缝合先寻找_Image Stitching

Graphcut 求解最佳缝合线&#xff1a; 主要参照硕士学位论文《基于不同视点样图的图像修复》 Graphcut 主要参照&#xff1a; http://blog.csdn.net/zouxy09/article/details/8532111 Graph cuts是一种十分有用和流行的能量优化算法&#xff0c;在计算机视觉领域普遍应用于…

.netcore 开发的 iNeuOS 物联网平台部署在 Ubuntu 操作系统,无缝跨平台

1. 概述参见前两篇文章&#xff1a;《iNeuOS完全使用.netcore开发&#xff0c;主要为企业、集成商打造从网关、边缘应用、云端建设的物联网/工业互联网平台产品级解决方案。面向应用场景&#xff1a;&#xff08;1&#xff09;嵌入式硬件网关的开发和部署&#xff0c;形成自己…

按照前序遍历和中序遍历构建二叉树

转载自&#xff1a;http://blog.csdn.net/sbitswc/article/details/26433051 Given preorder and inorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in the tree. There is an example._______7______/ …

刷新:重新发现.NET与未来

是新朋友吗&#xff1f;记得先点蓝字关注我哦&#xff5e;微软在比尔盖茨手中创立并崛起, 成为PC互联网时代的霸主&#xff0c;很多70&#xff0c;80后都有MVP Edi Wang 的体验<“ 当时的微软对我来说就是神的存在。因为我认识电脑到使用电脑的一切几乎都离不开这家伟大的公…

合并区间

题目描述 给出一个区间的集合&#xff0c;请合并所有重叠的区间。 示例 1: 输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].示例 2: 输入: [[1,4],[4,5]] 输出: [[1,5]] 解释: 区间 [1,4] 和 [4,5]…

程序员修神之路--设计一套RPC框架并非易事

菜菜哥&#xff0c;我最近终于把Socket通信调通了这么底层的东西你现在都会了&#xff0c;恭喜你离涨薪又进一步呀http协议不也是利用的Socket吗可以这么说&#xff0c;http协议是基于TCP协议的&#xff0c;底层的数据传输可以说是利用的socket既然Socket通信会了&#xff0c;那…

GPU Shader 编程基础

转载自&#xff1a;http://www.cnblogs.com/youthlion/archive/2012/12/07/2807919.html 几个基本概念&#xff1a; Vertex buffer&#xff1a;存储顶点的数组。当构成模型的所有顶点都放进vertex buffer后&#xff0c;就可以把vertex buffer送进GPU&#xff0c;然后GPU就可…

Azure pipeline 配置根据条件执行脚本

Azure pipeline 配置根据条件执行脚本Intro我的应用通过 azure pipeline 来做持续集成&#xff0c;之前已经介绍了根据不同分支去打包不同的package&#xff0c;具体的就不再这里详细介绍了&#xff0c;可以参考 Solution来看一下修改之后的 azure-pipelines.yaml 示例配置吧&a…

C# 8 新特性 - 可空引用类型

Nullable Reference Type.在写C#代码的时候&#xff0c;你可能经常会遇到这个错误&#xff1a; 但如果想避免NullReferenceException的发生&#xff0c;确实需要做很多麻烦的工作。 可空引用类型 Null Reference Type 所以&#xff0c;C# 8的可空引用类型就出现了。 C# 8可以让…

统计学习笔记(1) 监督学习概论(1)

原作品&#xff1a;The Elements of Statistical Learning Data Mining, Inference, and Prediction, Second Edition, by Trevor Hastie, Robert Tibshirani and Jerome Friedman An Introduction to Statistical Learning. by Gareth JamesDaniela WittenTrevor Hastie andR…

.NET Core 3.0之深入源码理解ObjectPool(一)

写在前面对象池是一种比较常用的提高系统性能的软件设计模式&#xff0c;它维护了一系列相关对象列表的容器对象&#xff0c;这些对象可以随时重复使用&#xff0c;对象池节省了频繁创建对象的开销。它使用取用/归还的操作模式&#xff0c;并重复执行这些操作。如下图所示&…

Deep Boltzmann Machines

转载自&#xff1a;http://blog.csdn.net/win_in_action/article/details/25333671 http://blog.csdn.net/zouxy09/article/details/8775518 深度神经网络&#xff08;Deep neural network&#xff09; 深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种…

.NET斗鱼直播弹幕客户端(下)

前言在上篇文章中&#xff0c;我们提到了如何使用 .NET连接斗鱼TV直播弹幕的基本操作。然而想要做得好&#xff0c;做得容易扩展&#xff0c;就需要做进一步的代码整理。本文将涉及以下内容&#xff1a;介绍如何使用 ReactiveExtensions&#xff08; Rx&#xff09;&#xff0c…

【 .NET Core 3.0 】框架之十 || AOP 切面思想

本文有配套视频&#xff1a;https://www.bilibili.com/video/av58096866/?p6前言上回《【 .NET Core3.0 】框架之九 || 依赖注入IoC学习 AOP界面编程初探》咱们说到了依赖注入Autofac的使用&#xff0c;不知道大家对IoC的使用是怎样的感觉&#xff0c;我个人表示还是比较可行…

[ASP.NET Core 3框架揭秘] 跨平台开发体验: Docker

对于一个 .NET Core开发人员&#xff0c;你可能没有使用过Docker&#xff0c;但是你不可能没有听说过Docker。Docker是Github上最受欢迎的开源项目之一&#xff0c;它号称要成为所有云应用的基石&#xff0c;并把互联网升级到下一代。Docker是dotCloud公司开源的一款产品&#…

统计学习笔记(4) 线性回归(1)

Basic Introduction In this chapter, we review some of the key ideas underlying the linear regression model, as well as the least squares approach that is most commonly used to fit this model. Basic form: “≈” means “is approximately modeled as”, to …