最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解C#中IAsyncDisposable接口的使用

 更新時(shí)間:2023年07月25日 09:42:33   作者:句幽  
在.NET Core 3.0的版本更新中,官方我們帶來(lái)了一個(gè)新的接口 IAsyncDisposable,下面小編就來(lái)和大家聊聊它的簡(jiǎn)單使用吧,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

.NET Core 3.0的版本更新中,官方我們帶來(lái)了一個(gè)新的接口 IAsyncDisposable。

小伙伴一看肯定就知道,它和.NET中原有的IDisposable接口肯定有著密不可分分的關(guān)系,且一定是它的異步實(shí)現(xiàn)版本。

那么.NET是為什么要在 .NET Core 3.0 (伴隨C# 8) 發(fā)布的同時(shí),帶來(lái)該接口呢? 還有就是該異步版本和原來(lái)的IDispose有著什么樣的區(qū)別呢? 到底在哪種場(chǎng)景下我們能使用它呢?

帶著這些問(wèn)題,我們今天一起來(lái)認(rèn)識(shí)一下這位"新朋友" —— IAsyncDisposable。

為了更好的了解它,讓我們先來(lái)回顧一下.NET中的資源釋放:

.NET的資源釋放

由于.NET強(qiáng)大的GC,對(duì)于托管資源來(lái)說(shuō)(比如C#的類實(shí)例),它的釋放往往不需要開(kāi)發(fā)人員來(lái)操心。

但是在開(kāi)發(fā)過(guò)程中,有時(shí)候我們需要涉及到非托管的資源,比如I/O操作,將緩沖區(qū)中的文本內(nèi)容保存到文件中、網(wǎng)絡(luò)通訊,發(fā)送數(shù)據(jù)包等等。

由于這些操作GC沒(méi)有辦法控制,所以也就沒(méi)有辦法來(lái)管理它們的生命周期。如果使用了非托管資源之后,沒(méi)有及時(shí)進(jìn)行釋放資源,那么就會(huì)造成內(nèi)存的泄漏問(wèn)題。

而.NET為我們提供了一些手段來(lái)進(jìn)行資源釋放的操作:

析構(gòu)函數(shù)

析構(gòu)函數(shù)在C#中是一個(gè)語(yǔ)法糖,在構(gòu)造函數(shù)前方加一個(gè)符號(hào)即代表使用析構(gòu)函數(shù) 。

public class ExampleClass
{
	public ExampleClass()
	{
	}
	~ExampleClass()	// 析構(gòu)函數(shù)
	{
		// 釋放非托管資源
	}
}

當(dāng)一個(gè)類申明了析構(gòu)函數(shù)了之后,GC將會(huì)對(duì)它進(jìn)行特殊的處理,當(dāng)該實(shí)例的資源被GC回收之前會(huì)調(diào)用析構(gòu)函數(shù)。(該部分內(nèi)容本文將不做過(guò)多介紹)

雖然析構(gòu)函數(shù)方法在某些需要進(jìn)行清理的情況下是有效的,但它有下面兩個(gè)嚴(yán)重的缺點(diǎn):

  • 只有在GC檢測(cè)到某個(gè)對(duì)象可以被回收時(shí)才會(huì)調(diào)用該對(duì)象的終結(jié)方法,這發(fā)生在不再需要資源之后的某個(gè)不確定的時(shí)間。這樣一來(lái),開(kāi)發(fā)人員可以或希望釋放資源的時(shí)刻與資源實(shí)際被終結(jié)方法釋放的時(shí)刻之間會(huì)有一個(gè)延遲。如果程序需要使用許多稀缺資源(容易耗盡的資源)或不釋放資源的代價(jià)會(huì)很高(例如,大塊的非托管內(nèi)存),那么這樣的延遲可能會(huì)讓人無(wú)法接受。
  • 當(dāng)CLR需要調(diào)用終結(jié)方法時(shí),它必須把回收對(duì)象內(nèi)存的工作推遲到垃圾收集的下一輪(終結(jié)方法會(huì)在兩輪垃圾收集之間運(yùn)行)。這意味著對(duì)象的內(nèi)存會(huì)在很長(zhǎng)一段時(shí)間內(nèi)得不到釋放。

因此,如果需要盡快回收非托管資源,或者資源很稀缺,或者對(duì)性能要求極高以至于無(wú)法接受在GC時(shí)增加額外開(kāi)銷,那么在這些情況下完全依靠析構(gòu)函數(shù)的方法可能不太合適。

而框架提供了IDisposable接口,該接口為開(kāi)發(fā)人員提供了一種手動(dòng)釋放非托管資源的方法,可以用來(lái)立即釋放不再需要的非托管資源。

IDisposable

.NET Framework 1.1開(kāi)始 ,.NET就為我們提供了IDispose接口。

使用該接口,我們可以實(shí)現(xiàn)名為Dispose的方法,進(jìn)行一些手動(dòng)釋放資源的操作(包括托管資源和非托管資源)。

public class ExampleClass:IDisposable
{
	private Stream _memoryStream = new MemoryStream();
	public ExampleClass()
	{
	}
	public void Dispose()
	{
		// 釋放資源
		myList.Clear();
		myData = null;
		_memoryStream.Dispose();	
	}
}

在C#中,我們除了可以手動(dòng)調(diào)用 xx.Dispose()方法來(lái)觸發(fā)釋放之外,還可以使用using的語(yǔ)法糖。

當(dāng)我們?cè)?visual studio 中添加IDisposable接口時(shí),它會(huì)提示我們使用是否使用“釋放模式”:

“釋放模式”所生成的代碼如下:

protected virtual void Dispose(bool disposing)
{
	if (!disposedValue)
	{
		if (disposing)
		{
			// TODO: 釋放托管狀態(tài)(托管對(duì)象)
		}
		// TODO: 釋放未托管的資源(未托管的對(duì)象)并重寫終結(jié)器
		// TODO: 將大型字段設(shè)置為 null
		disposedValue = true;
	}
}
// // TODO: 僅當(dāng)“Dispose(bool disposing)”擁有用于釋放未托管資源的代碼時(shí)才替代終結(jié)器
// ~ExampleClass()
// {
//     // 不要更改此代碼。請(qǐng)將清理代碼放入“Dispose(bool disposing)”方法中
//     Dispose(disposing: false);
// }
public void Dispose()
{
	// 不要更改此代碼。請(qǐng)將清理代碼放入“Dispose(bool disposing)”方法中
	Dispose(disposing: true);
	GC.SuppressFinalize(this);
}

釋放資源的代碼被放置在 Dispose(bool disposing) 方法中,你可以選用 析構(gòu)函數(shù) 或者 IDisposable 來(lái)進(jìn)行調(diào)用該方法。

這里說(shuō)一下:在 IDisposable 的實(shí)現(xiàn)中,有一句 GC.SuppressFinalize(this);。 這句話的意思是,告訴GC,不需要對(duì)該類的析構(gòu)函數(shù)進(jìn)行單獨(dú)處理了。也就是說(shuō),該類的析構(gòu)函數(shù)將不會(huì)被調(diào)用。因?yàn)橘Y源已經(jīng)在 Dispose() 中被我清理了。

異步時(shí)代

.NET Core開(kāi)始,就意味著.NET來(lái)到了一個(gè)全新的異步時(shí)代。無(wú)論是各種基礎(chǔ)類庫(kù)(比如System.IO)、AspNet Core、還是EFCore… 它們都支持異步操作,應(yīng)該說(shuō)是推薦異步操作。

在今天,假如一個(gè)新項(xiàng)目沒(méi)有使用 awaitasync。你都會(huì)覺(jué)得自己在寫假代碼。

現(xiàn)在越來(lái)越多的開(kāi)發(fā)者都愛(ài)上了這種異步方式:不阻止線程的執(zhí)行,帶來(lái)高性能的同時(shí)還完全不需要更改原有的編碼習(xí)慣,可謂是兩全其美。

所以從.NET Core 開(kāi)始到現(xiàn)在的.NET 5 ,每一次版本更迭都會(huì)有一批API提供了異步的版本。

IAsyncDisposable的誕生

為了提供這樣一種機(jī)制讓使用者能夠執(zhí)行資源密集型的處置操作,而不會(huì)長(zhǎng)期阻塞GUI應(yīng)用程序的主線程,我們讓操作成為了異步。

同樣,釋放資源的時(shí)候我們能否成為異步呢? 假如一次釋放操作會(huì)占耗費(fèi)太多的時(shí)間,那為什么我們不讓它去異步執(zhí)行呢?

為了解決這一問(wèn)題,同時(shí)更好的完善.NET異步編程的體驗(yàn),IAsyncDisposable誕生了。

它的用法與IDisposable非常的類似:

public class ExampleClass : IAsyncDisposable
{
	private Stream _memoryStream = new MemoryStream();
	public ExampleClass()
	{
	}
	public async ValueTask DisposeAsync()
	{
		await _memoryStream.DisposeAsync();
	}
}

當(dāng)然,using的語(yǔ)法糖同樣適用于它。不過(guò),由于它是異步編程的風(fēng)格,在使用時(shí)記得添加await關(guān)鍵字:

await using var s = new ExampleClass()
{
	// doing
};

當(dāng)然在 C# 8 以上,我們可以使用using作用域的簡(jiǎn)化寫法:

await using var s = new ExampleClass();
// doing

IAsyncDisposable與IDisposable的選擇

有一個(gè)關(guān)鍵點(diǎn)是: IAsyncDisposable 其實(shí)并沒(méi)有繼承于 IDisposable。

這就意味著,我們可以選擇兩者中的任意一個(gè),或者同時(shí)都要。

那么我們到底該選擇哪一個(gè)呢?

這個(gè)問(wèn)題其實(shí)很類似于EF剛為大家提供SaveChangesAsync方法的時(shí)候,到底我們?cè)撨x用SaveChangesAsync還是SaveChanges呢?

在以往同步版本的代碼中,我們往往會(huì)選擇SaveChanges同步方法。 當(dāng)來(lái)到了異步的環(huán)境,我們往往會(huì)選擇SaveChangesAsync。

所以在AspNet Core這個(gè)全流程異步的大環(huán)境下,我們的代碼潛移默化的就會(huì)更改為SaveChangesAsync。

IAsyncDisposable也是同理的,當(dāng)我們處于異步的環(huán)境中,所使用的資源提供了異步釋放的接口,那么我們肯定就會(huì)自然而然的使用IAsyncDisposable。

.NET 5 之后,大部分的類都具有了IAsyncDisposable的實(shí)現(xiàn)。比如:

  • Utf8JsonWriter、StreamWriter這些與文件操作有關(guān)的類;
  • DbContext這類數(shù)據(jù)庫(kù)操作類
  • Timer
  • 依賴注入的ServiceProvider
  • ………………

接下來(lái)的.NET版本中,我們也會(huì)看到AspNet Core中的Controller 等對(duì)于IAsyncDisposable提供支持。

可以預(yù)測(cè)是,在未來(lái)的.NET發(fā)展中,全異步的發(fā)展是必然的。后面越來(lái)越的已有庫(kù)會(huì)支持異步的所有操作,包括IAsyncDisposable的使用也會(huì)越來(lái)越頻繁。

Asp Net Core 依賴注入中的IAsyncDisposable

對(duì)于咱們使用AspNet Core的開(kāi)發(fā)人員來(lái)說(shuō),我們?cè)诖蠖鄶?shù)情況下都會(huì)依賴于框架所提供的依賴注入功能。

而依賴注入框架,會(huì)在作用域釋放的時(shí)候,自動(dòng)去調(diào)用所注入服務(wù)的釋放接口IDisposable。

比如我們把 DbContext 注入之后,其實(shí)就只管使用就行了,從來(lái)不會(huì)關(guān)心它的Dispose問(wèn)題。 相對(duì)于傳統(tǒng)using(var dbContext = new MyDbContext)的方式要省心很多,也不會(huì)擔(dān)心忘記寫釋放而導(dǎo)致的數(shù)據(jù)庫(kù)連接未釋放的問(wèn)題。

那么,當(dāng)IAsyncDisposable出現(xiàn)之后呢?會(huì)出現(xiàn)什么情況:

public void ConfigureServices(IServiceCollection services)
{
	services.AddControllers();
	services.AddScoped<DemoDisposableObject>();	// 注入測(cè)試類	
}
public class DemoDisposableObject : IAsyncDisposable
{
	public ValueTask DisposeAsync()
	{
		 code here  
		// 當(dāng)完成一次http 請(qǐng)求后,該方法會(huì)自動(dòng)調(diào)用
	}
}

當(dāng)我們實(shí)現(xiàn)了IAsyncDisposable之后,會(huì)被自動(dòng)調(diào)用。

那么如果 IAsyncDisposableIDisposable 一同使用呢?

public class DemoDisposableObject : IAsyncDisposable,IDisposable
{
	public void Dispose()
	{
		code here  
	}
	public ValueTask DisposeAsync()
	{
		code here  
	}
}

這樣的結(jié)果是:只有DisposeAsync方法會(huì)被調(diào)用。

為什么會(huì)有這樣的結(jié)果呢? 讓我們一起來(lái)扒開(kāi)它的面紗。

以下代碼位于 AspNet Core源碼

public class RequestServicesFeature : IServiceProvidersFeature, IDisposable, IAsyncDisposable
{
	public IServiceProvider RequestServices
	{
		get
		{
			if (!_requestServicesSet && _scopeFactory != null)
			{
				_scope = _scopeFactory.CreateScope();
				……………………
			}
			return _requestServices!;
		}
	}
	public ValueTask DisposeAsync()
	{
		switch (_scope)
		{
			case IAsyncDisposable asyncDisposable:
				var vt = asyncDisposable.DisposeAsync();
				………………
				break;
			case IDisposable disposable:
				disposable.Dispose();
				break;
		}
		……………………
		return default;
	}
	public void Dispose()
	{
		DisposeAsync().AsTask().GetAwaiter().GetResult();
	}
}

為了方便起見(jiàn),我省略了部分代碼。 這里的關(guān)鍵代碼在于: DisposeAsync()方法,它會(huì)在內(nèi)部進(jìn)行判斷,IServiceScope是否為IAsyncDisposable類型。如果是,則會(huì)采用它的IServiceScope的異步釋放方法。

所以本質(zhì)上還是回到了官方依賴注入框架中IServiceScope的實(shí)現(xiàn):

以下代碼位于 DependencyInjection源碼

internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IAsyncDisposable, IServiceScopeFactory
{
	public ValueTask DisposeAsync()
	{
		List<object> toDispose = BeginDispose();
		if (toDispose != null)
		{
			try
			{
				for (int i = toDispose.Count - 1; i >= 0; i--)
				{
					object disposable = toDispose[i];
					if (disposable is IAsyncDisposable asyncDisposable)
					{
						ValueTask vt = asyncDisposable.DisposeAsync();
						if (!vt.IsCompletedSuccessfully)
						{
							return Await(i, vt, toDispose);
						}
						// If its a IValueTaskSource backed ValueTask,
						// inform it its result has been read so it can reset
						vt.GetAwaiter().GetResult();
					}
					else
					{
						((IDisposable)disposable).Dispose();
					}
				}
			}
			catch (Exception ex)
			{
				return new ValueTask(Task.FromException(ex));
			}
		}
		return default;
	}
}

可以看出新版本的IServiceScope實(shí)現(xiàn)一定是繼承了IAsyncDisposable接口,所以在上面的AspNet Core的代碼里,它一定會(huì)調(diào)用IServiceScopeDisposeAsync()方法。

IServiceScope的默認(rèn)實(shí)現(xiàn)在異步釋放時(shí)會(huì)進(jìn)行判斷:如果注入的實(shí)例為IAsyncDisposable則調(diào)用DisposeAsync(),否則判斷是否為IDisposable

這也解釋了為什么我們?cè)谏厦嫱瑫r(shí)實(shí)現(xiàn)兩個(gè)釋放接口,卻只有異步版本的會(huì)被調(diào)用。

總結(jié)

在上面的文章中,我們了解到IAsyncDisposable作為.NET異步發(fā)展中一個(gè)重要的新接口,在應(yīng)用上會(huì)被越來(lái)越頻繁的使用,它將逐步完善.NET的異步生態(tài)。

當(dāng)存在下方的情況時(shí),我們應(yīng)該優(yōu)先考慮來(lái)使用它:

  • 當(dāng)內(nèi)部擁有的資源具有對(duì)IAsyncDisposable的實(shí)現(xiàn)(比如Utf8JsonWriter等),我們可以采用使用IAsyncDisposable來(lái)對(duì)他們進(jìn)行釋放。
  • 當(dāng)在異步的大環(huán)境下,新編寫一個(gè)需要釋放資源的類,可以優(yōu)先考慮使用IAsyncDisposable。

現(xiàn)在.NET的很多類庫(kù)都已經(jīng)同時(shí)支持了IDisposableIAsyncDisposable。而從使用者的角度來(lái)看,其實(shí)調(diào)用任何一個(gè)釋放方法都能夠達(dá)到釋放資源的目的。就好比DbContextSaveChangesSaveChangesAsync

但是從未來(lái)的發(fā)展角度來(lái)看,IAsyncDisposable會(huì)成使用的更加頻繁。因?yàn)樗鼞?yīng)該能夠優(yōu)雅地處理托管資源,而不必?fù)?dān)心死鎖。

而對(duì)于現(xiàn)在已有代碼中實(shí)現(xiàn)了IDisposable的類,如果想要使用IAsyncDisposable。建議您同時(shí)實(shí)現(xiàn)兩個(gè)接口,已保證使用者在使用時(shí),無(wú)論調(diào)用哪個(gè)接口都能達(dá)到效果,而達(dá)到兼容性的目的。

類似于下方代碼:

節(jié)選自Stream類的源碼

public void Dispose() => Close();
public virtual void Close()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}
public virtual ValueTask DisposeAsync()
{
    try
    {
        Dispose();
        return default;
    }
    catch (Exception exc)
    {
        return ValueTask.FromException(exc);
    }
}

到此這篇關(guān)于詳解C#中IAsyncDisposable接口的使用的文章就介紹到這了,更多相關(guān)C# IAsyncDisposable內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 在.NET?WebService中跨域CORS問(wèn)題的解決方案

    在.NET?WebService中跨域CORS問(wèn)題的解決方案

    在現(xiàn)代的Web應(yīng)用程序開(kāi)發(fā)中,跨域資源共享(Cross-Origin?Resource?Sharing,?CORS)問(wèn)題是開(kāi)發(fā)者經(jīng)常遇到的一個(gè)挑戰(zhàn),在這篇博客中,我們將深入探討如何在?.NET?WebService?中解決CORS問(wèn)題,幫助開(kāi)發(fā)者順利實(shí)現(xiàn)跨域請(qǐng)求,需要的朋友可以參考下
    2024-05-05
  • C#怎樣才能實(shí)現(xiàn)窗體最小化到托盤呢?

    C#怎樣才能實(shí)現(xiàn)窗體最小化到托盤呢?

    C#怎樣才能實(shí)現(xiàn)窗體最小化到托盤呢?...
    2007-03-03
  • C#創(chuàng)建背景色漸變窗體的方法實(shí)例

    C#創(chuàng)建背景色漸變窗體的方法實(shí)例

    在窗體設(shè)計(jì)時(shí),可以通過(guò)設(shè)置窗體的BackColor屬性來(lái)改變窗口的背景顏色,但是該屬性改變后整個(gè)窗體的客戶區(qū)都會(huì)變成這種顏色,這樣顯得非常單調(diào),本文給大家介紹了C#創(chuàng)建背景色漸變窗體的方法實(shí)例,需要的朋友可以參考下
    2024-04-04
  • C# Onnx CenterNet實(shí)現(xiàn)目標(biāo)檢測(cè)的示例詳解

    C# Onnx CenterNet實(shí)現(xiàn)目標(biāo)檢測(cè)的示例詳解

    這篇文章主要為大家詳細(xì)介紹了C# Onnx CenterNet實(shí)現(xiàn)目標(biāo)檢測(cè)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • C#中接口(interface)的理解

    C#中接口(interface)的理解

    C#中接口(interface)的理解...
    2007-03-03
  • C#中的協(xié)變與逆變方式

    C#中的協(xié)變與逆變方式

    協(xié)變和逆變是C#中處理泛型類型參數(shù)可變性的兩個(gè)重要概念,協(xié)變?cè)试S將派生類型的泛型參數(shù)轉(zhuǎn)換為基類型的泛型參數(shù),而逆變?cè)试S將基類型的泛型參數(shù)轉(zhuǎn)換為派生類型的泛型參數(shù),通過(guò)協(xié)變和逆變,可以提高代碼的靈活性和可重用性,但也需要注意類型參數(shù)的限制和安全性
    2024-12-12
  • 詳解C#如何實(shí)現(xiàn)分割視頻

    詳解C#如何實(shí)現(xiàn)分割視頻

    這篇文章主要為大家詳細(xì)介紹了C#如何實(shí)現(xiàn)將視頻文件分割成一幀幀圖片的方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • C#基于WebSocket實(shí)現(xiàn)聊天室功能

    C#基于WebSocket實(shí)現(xiàn)聊天室功能

    這篇文章主要為大家詳細(xì)介紹了C#基于WebSocket實(shí)現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#如何優(yōu)雅的對(duì)WinForm窗體應(yīng)用程序進(jìn)行權(quán)限控制

    C#如何優(yōu)雅的對(duì)WinForm窗體應(yīng)用程序進(jìn)行權(quán)限控制

    經(jīng)常會(huì)出現(xiàn)winfrom頁(yè)面需要加載權(quán)限樹(shù),下面這篇文章主要給大家介紹了關(guān)于C#如何優(yōu)雅的對(duì)WinForm窗體應(yīng)用程序進(jìn)行權(quán)限控制的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • 詳解C#如何自定義書寫中間件

    詳解C#如何自定義書寫中間件

    中間件是一種裝配到應(yīng)用管道以處理請(qǐng)求和響應(yīng)的軟件,是介于request與response處理過(guò)程之間的一個(gè)插件,本文主要介紹了如何自定義書寫中間件,需要的可以參考下
    2023-08-08

最新評(píng)論

承德县| 郓城县| 岫岩| 汉寿县| 千阳县| 全南县| 茂名市| 绵阳市| 社旗县| 永丰县| 淄博市| 泰顺县| 白山市| 东乡| 布尔津县| 赤壁市| 婺源县| 巴林左旗| 平遥县| 屏东市| 吴旗县| 台中县| 屏山县| 东至县| 太保市| 花垣县| 抚州市| 东乡| 平顶山市| 永清县| 于田县| 鄱阳县| 兰州市| 罗源县| 望谟县| 郓城县| 专栏| 容城县| 神木县| 双桥区| 论坛|