1.概念
概念
生活中的“控制反轉(zhuǎn)”:自己發(fā)電和用電網(wǎng)的電。
依賴注入(Dependency Injection,Dl)是控制反轉(zhuǎn):(Inversion of Control,l0c)思想的實現(xiàn)方式。
依賴注入簡化模塊的組裝過程,降低模塊之間的耦合度
自己發(fā)電的代碼
var connSettings =ConfigurationManager.ConnectionStrings["connstr1"];
string connStr= connsettings.ConnectionString;
SqlConnection conn = new SqlConnection(connstr);
缺點是?
你需要對一切流程很清楚。
代碼控制反轉(zhuǎn)的目的
'怎樣創(chuàng)建XX對象”---->“我要XX對象
兩種實現(xiàn)方式:
1)服務定位器(ServiceLocator);
2)依賴注入(Dependency Injection,Dl);
暢想Demo
服務定位器
IDbConnection conn=ServiceLocator.GetService();
依賴注入
class Demo
{
// 創(chuàng)建對象之后,框架自動為他賦值
public lDbConnection Conn { get; set; }
public void insertDB()
{
IDbCommand cmd= Conn.CreateCommand();
}
}
第二部分 依賴注入
DI幾個概念
服務(service):對象;
注冊服務:服務容器:負責管理注冊的服務;
查詢服務:創(chuàng)建對象及關(guān)聯(lián)對象;
對象生命周期:Transient(瞬態(tài),每次獲取都是一個新的對象);scoped(范圍,在這個范圍之內(nèi),每次都是同一個對象);singleton(單例,無論誰獲取這個服務,都是同一個對象);
.NET 中使用DI
1、測試代碼見備注
2、根據(jù)類型來獲取和注冊服務可以分別指定服務類型(servicetype)和實現(xiàn)類型(implementationtype)。這兩者可能相同,也可能不同。服務類型可以是類,也可以是接口建議面向接口編程,更靈活。
3、.NET控制反轉(zhuǎn)組件取名為DependencyInjection但它包含ServiceLocator的功能。
功能測試類
調(diào)用:
運行結(jié)果:
.NET 中使用DI 2
1、Install-Package Microsoft.Extensions.DependencyInjection
2、using Microsoft.Extensions.DependencyInjection
3、ServiceCollection用來構(gòu)造容器對象IServiceProvider。調(diào)用ServiceCollection的BuildserviceProvider()創(chuàng)建的ServiceProvider,可以用來獲取BuildserviceProvider()之前Servicecollection中的對象。示例代碼見備注。
示例
1.安裝nuget 包
2、引入包
3、構(gòu)造容器對象
目前看起來 沒有任何意義
一行new 就搞定的代碼!! 寫了八行
第三部分,依賴注入
生命周期
1、給類構(gòu)造函數(shù)中打印,看看不同生命周期的對象創(chuàng)建使用serviceProvider.CreateScope()創(chuàng)建Scope.
2、如果一個類實現(xiàn)了IDisposable接口,則離開作用域之后容器會自動調(diào)用對象的Dispose方法,
3、不要在長生命周期的對象中引用比它短的生命周期的對象。在ASP.NET Core中,這樣做默認會拋異常。
4、生命周期的選擇:如果類無狀態(tài),建議為singleton;如果類有狀態(tài),且有Scope控制,建議為Scoped,因為通常這種Scope控制下的代碼都是運行在同一個線程中的,沒有并發(fā)修改的問題;在使用Transient的時候要謹慎。
5、.NET注冊服務的重載方法很多,看著文檔琢磨吧
測試生命周期
AddTransient 模式
運行結(jié)果:
測試2
運行結(jié)果:
證明,每次調(diào)用GetService 都會返回一個新的對象
AddSingleton 模式
運行結(jié)果:
AddScope模式
運行結(jié)果:
表明為同一個對象
再次創(chuàng)建一個Scope
運行結(jié)果:
不同Scope 中 進行對比
運行結(jié)果:
不同范圍內(nèi)拿到的對象不是同一個
沒有成員變量 ,沒有屬性 :無狀態(tài)類。 建議為Singleton,單線程不考慮并發(fā)問題。
如果類有狀態(tài),且有Scope控制,建議為Scope,通常Scope 控制的代碼。都是運行在同一個線程內(nèi)的。
Transient 需要謹慎,比較耗費內(nèi)存
服務定位器
其他注冊方法:
服務類型和實現(xiàn)類型不一致的注冊
簡單看看其他Add*方法
方式一
運行結(jié)果:
方式二
結(jié)果完全相同
單例方式:
IServiceProvider的服務定位器方法:
T GetService()如果獲取不到對象,則返回null。
object GetService(Type serviceType)
T GetRequiredservice()如果獲取不到對象,則拋異常
object GetRequiredservice(Type serviceType)
lEnumerableGetServices()適用于可能有很多滿足條件的服務
lEnumerableGetServices(Type serviceType)
示例:
T GetService()
object GetService(Type serviceType)
object GetRequiredservice(Type serviceType)
lEnumerableGetServices()
目前來說只有一個
改為實現(xiàn)類:
未滿足,結(jié)果為空
注冊多個服務
因為還有另外一個實現(xiàn)類:
運行
結(jié)果:
此時兩個服務都將打印
注冊多個服務后,再打印結(jié)果會發(fā)生什么情況呢
此時是以最后一個為準
使用getrequiredService 也是相同結(jié)果
第四部分
DI魅力漸顯:依賴注入
1、依賴注入是有“傳染性”的,如果一個類的對象是通過DI創(chuàng)建的,那么這個類的構(gòu)造函數(shù)中聲明的所有服務類型的參數(shù)都會被DI賦值;但是如果一個對象是程序員手動創(chuàng)建的,那么這個對象就和DI沒有關(guān)系,它的構(gòu)造函數(shù)中聲明的服務類型參數(shù)就不會被自動賦值。
2、.NET的DI默認是構(gòu)造函數(shù)注入。
3、舉例:編寫一個類,連接數(shù)據(jù)庫做插入操作,并且記錄日志(模擬的輸出),把Dao、日志都放入單獨的服務類。connstr見備注。
新建項目,演示依賴注入的“傳染性”
裝包
編寫代碼
controller方法中 中使用
調(diào)用
運行結(jié)果:
好處,當我們更改實現(xiàn)類時,不需要更改代碼
新增從數(shù)據(jù)庫讀取配置
此時只需要更改代碼配置
降低模塊之間的耦合文章來源:http://www.zghlxwxcb.cn/news/detail-831413.html
運行結(jié)果:文章來源地址http://www.zghlxwxcb.cn/news/detail-831413.html
到了這里,關(guān)于楊中科 .netcore 依賴注入的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!