از رابط IAsyncDisposable برای دور انداختن اشیاء به روشی غیر مسدود کننده و کارآمدتر کردن برنامه های NET خود استفاده کنید.
Dispose و Finalize دو روش برای انتشار منابعی هستند که توسط برنامههای NET و .NET Core در چارچوب CLR اجرا میشوند. اگر برنامه شما حاوی منابع مدیریت نشده است، باید کد لازم را بنویسید تا آن منابع را به صراحت آزاد کنید.
از آنجایی که نهاییسازی غیر قطعی است و نهاییکنندهها از نظر مصرف منابع گران هستند، روش Dipose بر نهاییکننده ترجیح داده میشود. میتوانید از روش Dispose در هر نوعی که رابط IDisposable را پیادهسازی میکند، استفاده کنید. در نهایت، با ظهور برنامه نویسی ناهمزمان، دات نت به یک همتای ناهمزمان برای IDisposable نیاز داشت. بنابراین رابط IAsyncDisposable معرفی شد.
این مقاله رابط IAsyncDisposable و نحوه کار با آن در C# را مورد بحث قرار می دهد. برای کار با نمونه کدهای ارائه شده در این مقاله، باید Visual Studio 2022 را در سیستم خود نصب کنید. اگر قبلاً نسخهای ندارید، میتوانید Visual Studio 2022 را از اینجا بارگیری کنید.
یک پروژه برنامه کاربردی کنسول در Visual Studio 2022 ایجاد کنید
ابتدا، اجازه دهید یک پروژه برنامه کاربردی کنسول NET Core در ویژوال استودیو ایجاد کنیم. با فرض اینکه Visual Studio 2022 در سیستم شما نصب شده است، مراحل ذکر شده در زیر را برای ایجاد یک پروژه برنامه کاربردی کنسول NET Core جدید دنبال کنید.
- Visual Studio IDE را راه اندازی کنید.
- روی “ایجاد پروژه جدید” کلیک کنید.
- در پنجره “ایجاد یک پروژه جدید”، “Console App” را از لیست الگوهای نمایش داده شده انتخاب کنید.
- بعدی را کلیک کنید.
- در پنجره “پیکربندی پروژه جدید خود” که در ادامه نشان داده شده است، نام و مکان پروژه جدید را مشخص کنید.
- در پنجره “اطلاعات اضافی”، .NET 6.0 را به عنوان زمان اجرا انتخاب کنید و روی Next کلیک کنید
- روی ایجاد کلیک کنید.
این یک پروژه برنامه کاربردی کنسول .NET Core جدید ایجاد می کند. ما از این پروژه برای کار با رابط IAsyncDisposable در بخشهای بعدی این مقاله استفاده خواهیم کرد.
از IDisposable به IAsyncDisposable
اینترفیس IDisposable از همان روزهای اولیه دات نت فریم ورک، به طور دقیق از .NET Framework 1.0 وجود داشته است. احتمالاً هنگام طراحی کلاسهای خود در .NET و NET Core اغلب از این رابط استفاده کردهاید. اگر کلاس شما رابط IDisposable را پیاده سازی می کند، توصیه می شود که متد Dispose را به صراحت فراخوانی کنید.
با این حال، در طول سال ها، بسیاری از ویژگی های جدید به .NET Framework اضافه شده است. از آنجایی که multithreading به منابع نیاز داشت، برنامهنویسی ناهمزمان به ترکیب اضافه شد. برنامه نویسی ناهمزمان می تواند عملکرد و پاسخگویی برنامه شما را بهبود بخشد زیرا رشته فراخوان می تواند به انجام سایر عملیات ها ادامه دهد در حالی که روشی که به صورت ناهمزمان خوانده می شود به اجرا ادامه می دهد.
انواعی که رابط IDisposable را پیاده سازی می کنند منابع را به طور همزمان آزاد می کنند و بنابراین می توانند سایر رشته های در حال اجرا در سیستم را مسدود کنند. علاوه بر این، اگر نتوانید یک منبع یکبار مصرف ناهمزمان را از بین ببرید، ممکن است به بن بست نیز منجر شود. رابط IAsyncDisposable نیاز به آزادسازی منابع به صورت ناهمزمان را برطرف می کند.
چه زمانی باید از IAsyncDisposable استفاده کنید؟
شما باید از IAsyncDisposable فقط زمانی استفاده کنید که کلاسی دارید که باید منابع را به صورت ناهمزمان آزاد کند. به عبارت دیگر، اگر کلاس شما (یا هر یک از زیر کلاسهای آن) منابعی را که IAsyncDisposable را نیز پیادهسازی میکنند، اختصاص میدهد، باید از IAsyncDisposable استفاده کنید. در این صورت، باید مطمئن شوید که متد DisposeAsync در کلاس پایه مجازی اعلام شده است.
بهعنوان مثال، وقتی با جریانهای ناهمزمان و نمونههایی از منابع مدیریتنشده کار میکنید، باید از مزایای IAsyncDisposable استفاده کنید که به منابع زیادی نیاز دارند و باید پاکسازی شوند. می توانید از روش DisposeAsync این رابط برای انتشار چنین منابعی استفاده کنید.
پیاده سازی رابط IAsyncDisposable
رابط IAsyncDisposable متد DisposeAsync را تعریف می کند. توجه داشته باشید که متد DisposeAsync یک ValueTask را برمی گرداند که یک عملیات دفع ناهمزمان را نشان می دهد. توجه داشته باشید که هر کلاس غیر مهر و موم شده، به عنوان مثال، هر کلاسی که می تواند گسترش یابد، باید یک متد اضافی به نام DisposeAsyncCore داشته باشد که یک ValueTask را نیز برمی گرداند.
یک پیاده سازی معمولی DisposeAsync باید به این شکل باشد:
public async ValueTask DisposeAsync()
{
// Perform async cleanup here
await DisposeAsyncCore();
// Dispose all unmanaged resources
Dispose(false);
GC.SuppressFinalize(this);
}
بنابراین، میتوانید کد ناهمزمان خود را مانند مثال زیر بنویسید و اشیاء عملیات به صورت ناهمزمان حذف میشوند.
await using (SqlConnection dbConnection = new SqlConnection(connectionString))
{
// The connection instance will be disposed asynchronously when the
// program encounters the end of the using block.
}
به کلمه کلیدی await که قبل از عبارت use در قطعه کد قبلی استفاده شده است توجه کنید. کلمه کلیدی await در اینجا به بلوک استفاده کننده اطلاع می دهد که DisposeAsync را فراخوانی کند و هنگامی که کنترل به پایان بلوک استفاده می رسد، Dispose نمی کند.
چه زمانی باید IAsyncDisposable و IDisposable را پیاده سازی کنید؟
مایکروسافت توصیه می کند که هر دو رابط IAsyncDisposable و IDisposable را در کد خود پیاده سازی کنید. شما نباید IAsyncDisposable را به عنوان جایگزینی برای رابط IDisposable در نظر بگیرید. در عوض، باید IAsyncDisposable را تنها راه دیگری برای اجرای الگوی دور ریختن در نظر بگیرید.
اگر متد Dispose را پیادهسازی نکنید، هر کدی که در زمینه غیرهمگام اجرا نمیشود، روی روش DisposeAsync مسدود میشود تا روش DisposeAsync بهطور همزمان اجرا شود. بهعلاوه، وقتی از کانتینرهای IoC (وارونگی کنترل) استفاده میکنید و اگر کانتینر شما به طور همزمان از بین رفته است، ممکن است یک استثنا در زمان اجرا ایجاد شود زیرا روش DisposeAsync هرگز فراخوانی نمیشود.
همانطور که حالت های مایکروسافت در . مستندات NET:
هنگام پیادهسازی رابط IAsyncDisposable معمول است که کلاسها رابط IDisposable را نیز پیادهسازی کنند. یک الگوی اجرای خوب رابط IAsyncDisposable این است که برای دفع همزمان یا ناهمزمان آماده شود. تمام راهنماییها برای اجرای الگوی دور ریختن در مورد اجرای ناهمزمان نیز اعمال میشود.
اجرای دفع همزمان و ناهمزمان در NET
لیست کد زیر نشان میدهد که چگونه میتوانید یک الگوی دفع همزمان و ناهمزمان را در کد خود پیادهسازی کنید:
public class Example : IDisposable, IAsyncDisposable
{
private FileStream fileStream =
new FileStream("D:\\test.txt", FileMode.Create);
public void Dispose()
{
// Write code here to dispose resources synchronously
fileStream.Dispose();
}
public async ValueTask DisposeAsync()
{
// Write code here to dispose resources asynchronously
await fileStream.DisposeAsync();
}
}
رابط System.IAsyncDisposable با C# 8.0 منتشر شد. مشابه IDisposable، باید اشیاء IAsyncDisposable را در پایان درخواست HTTP دور بریزید. باید GC.SupressFinalize(this) را در روش DisposeAsync یا DisposeAsync خود فراخوانی کنید تا جمعآورکننده زباله بعداً نیازی به تماس با ویرانگر نداشته باشد.
پست های مرتبط
نحوه کار با IAsyncDisposable در NET 6
نحوه کار با IAsyncDisposable در NET 6
نحوه کار با IAsyncDisposable در NET 6