日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core 注册单例方案

發(fā)布時間:2023/12/4 asp.net 68 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core 注册单例方案 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一個單例是沒有公共構(gòu)造函數(shù)的,只能通過靜態(tài)的 Instance?屬性獲取,這是單例的標(biāo)準(zhǔn)初衷,一個單例是不想讓別人調(diào)用它的構(gòu)造函數(shù)的。但是 aspnetcore?中提供的?AddSingleton<TService, TImplementation>() ,只提供了類型,而無法注入對象實例,單實例對象還是要框架深層構(gòu)造的,這實際上并不是安全的做法。?

如果使用了標(biāo)準(zhǔn)的單例設(shè)計方法,則無法由框架直接生成單實例,這就需要使用點小技巧了。?

單例設(shè)計

public class Singleton<T> where T : class {protected static T instance;protected static object locker = new object();public static T Instance{get{if (instance == null){lock (locker){if (instance == null) //防止線程重入{IEnumerable<ConstructorInfo> constructors = typeof(T).GetTypeInfo().DeclaredConstructors;ConstructorInfo ci = constructors.ToList()[0];instance = ci.Invoke(new object[] { }) as T;}}}return instance;}}protected Singleton(){IEnumerable<ConstructorInfo> constructors = typeof(T).GetTypeInfo().DeclaredConstructors;constructors.ActionForeach(c => {if (c.IsPublic){throw new InvalidOperationException("禁止從public構(gòu)造函數(shù)中實例化!");}});}}

以上要點有三個:

1?使用次 if?判斷和 locker?保護(hù),防止線程重入時構(gòu)造多個實例,確保唯一性;

2?在基類中,使用反射調(diào)用子類的構(gòu)造函數(shù)完成實例化;

3 基類的構(gòu)造函數(shù)是受保護(hù)的,它會檢查,禁止子類的公共構(gòu)造函數(shù)調(diào)用。

第3條隱藏了一個知識點:子類在初始化實例時,默認(rèn)會調(diào)用基類的構(gòu)造函數(shù)。

因為以上三條機制確保了單例的唯一性,所以反射只會在第一次使用時調(diào)用,對性能的影響可以忽略不計。

?

單例的使用

使用起來非常簡單

public class Root:Singleton<Root> {protected Root() { }public void DoSomething() {Console.WriteLine("I feel very happy, cus I'm unique."); } }

假設(shè)有一個類,叫做Root,由于業(yè)務(wù)需要,它必須要以單例實現(xiàn),顧名思義,根只能有一個。

如果不重寫 protected?構(gòu)造函數(shù),則可能發(fā)生以下情況:

Root root = new Root();

這是被禁止的,萬一忘記寫了 protected Root(){}?這一行,就會拋出異常,可見在??Singleton<T>?中進(jìn)行判斷,是十分有必要的。

在業(yè)務(wù)需要的地方,就可以用通常使用的單例模式來調(diào)用 :

Root.Instance.DoSomething();

至此,單例模式完成。

一個真實的業(yè)務(wù)場景

假設(shè)主模塊是?Main.dll,?它是一個 aspnetcore?工程, 它調(diào)用了?A.dll?作為它的類庫。由于某種原因,Root?類必須要在?Main?工程中實現(xiàn),而不能放到?A?工程中。但是A工程要用到?Root?的方法。如果讓?A?工程來引用? Main?工程,這就是反向引用了,這會形成循環(huán)引用,是不被允許的。

所以我們可以把 Root?的方法抽象出接口來,注冊到?aspnet?框架中,我們可以這樣做:

在?A.csproj?中,暴露接口給自己調(diào)用:

public interface IRoot {void DoSomething(); }

在 Main.csproj?中實現(xiàn)這個接口:

class Root:Singleton<Root>, IRoot {protected Root() { }public void DoSomething() {Console.WriteLine("I feel very happy, cus I'm unique.");} }

然后就是注冊了,在 Main.csproj?工程的?Startup.cs?文件的??ConfigureServices?方法中進(jìn)行注冊:

public void ConfigureServices(IServiceCollection services) {services.AddControllersWithViews();services.AddSession();//...其他代碼services.AddSingleton<IRoot, Root>(); }

這樣就可以了嗎? no no no ,?這樣肯定是不行的,因為前面我們設(shè)計的單例,是這樣使用的: Root.Instance.DoSomething();? 而不是 Root root = new Root();?

這會導(dǎo)致注入失敗,因為框架注冊要求 Root 有一個公共無參構(gòu)造函數(shù),況且它并不知道Root有個靜態(tài)屬性 Instance ,而且只能通過 Instance?來訪問。

單例注入方案

下面說到正題了,既然不能直接注冊單例,我們可以使用一個中間接口來注入,這個中間接口提供了單例的訪問對象,而且它擁有一個沒有寫出來的默認(rèn)公共構(gòu)造方法,它的構(gòu)造函數(shù),與 Root 類的構(gòu)造函數(shù),毫無關(guān)系,所以可以由框架創(chuàng)建。

在 A.csproj?工程中定義:

public interface IRootProvider {IRoot Root { get; } }

在?Main.csproj?中實現(xiàn):

public class RootProvider : IRootProvider {public IRoot Root { get => SomeNamespace.Root.Instance; } }

然后再注冊:

public void ConfigureServices(IServiceCollection services) {services.AddControllersWithViews();services.AddSession();//...其他代碼services.AddScoped<IRootProvider, RootProvider>();services.AddScoped<ISomeService, SomeService>(); }

look,?我們已經(jīng)不需要使用?AddSingleton?來注入了,因為? RootProvider?不必是單實例的。?

在?A.csproj? 中愉快地使用:

public class SomeService:ISomeService {private IRoot root;public SomeService(IRootProvider rootProvider){this.root = rootProvider.Root;}public void SomeBusiness(){this.root.DoSomething();} } SomeService 是在主模塊中注入的服務(wù),在主模塊中構(gòu)造,構(gòu)造的前提是要有一個 IRootProvider 的實例,同時 IRootProvider 要在它的前一行注冊,這個很重要。 到這里,本文就結(jié)束了,但我還是想啰嗦一下:在A中使用的 IRoot root 一點也看不出單例的痕跡,因為 IRoot 只是一個業(yè)務(wù)接口;同時 IRootProvider 也只提供了 IRoot 的 get 方法, 所以對于 A 模塊的開發(fā)者,完全不必知道 Root 的存在,更不必知道什么 Singleton<Root> 跟 Instance 的破事。我們已經(jīng)完全隱藏了單例模式的實現(xiàn),這是解決這個問題附帶的收獲。這個設(shè)計是不是徹底實現(xiàn)了 面向接口編程 的規(guī)范? 快夸我吧! 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的ASP.NET Core 注册单例方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。