اشتراکها
اشتراکها
بررسی Blazor United
یکی دیگر از ویژگیهای جدید C# 8.0، پشتیبانی از using declarations (اعلانهای using) در مقابل using statements (عبارات using) پیشین است که سبب میشود بتوان کدهای کمتری را برای تعریف آنها نوشت.
مثالی از using declarations
تا پیش از C# 8.0، روش متداول کار با عبارات using به صورت زیر است و به آن استفاده از using statements گفته میشود:
که در نهایت پس از پایان این قطعه کد، هر دو شیء file و reader به صورت خودکار Dispose میشوند.
اکنون در C# 8.0 میتوان قطعه کد فوق را به کمک using declarations به صورت زیر خلاصه کرد:
که در اینجا پرانتزها و همچنین {} ها، حذف شدهاند.
میدان دید using declarations
پس از این تغییرات، سؤال مهمی که مطرح میشود این است: متغیرهایی که توسط using declaration تعریف میشوند، تا چه زمانی زنده نگه داشته میشوند. به عبارتی متد UsingOldScope آیا همانند متد UsingNewScope عمل میکند؟ آیا متغیر buffer آن همانند متد UsingOldScope خارج از میدان دید usingها قرار میگیرد؟
زمانیکه از using statements استفاده میشود (مانند متد UsingOldScope)، توسط آن یک scope نیز تعریف میشود (داخل {} ها) که در پایان آن، کار فراخوانی متد Dispose اشیاء IDisposable ارجاعی، به صورت خودکار انجام میشود. این فراخوانی نیز توسط کامپایلر در داخل یک قطعه کد try/finally صورت میگیرد تا حتی اگر در این بین استثنائی نیز رخ داد، حتما متد Dispose فراخوانی گردد.
اما زمانیکه از using declarations استفاده میشود (مانند متد UsingNewScope)، دیگر این {} را نداریم. اینبار scope تعریف شده، تا «پایان متد» ادامه پیدا میکند و سپس متد Dispose اشیاء ارجاعی، فراخوانی میگردد. بدیهی است در اینجا نیز همانند قبل، همان قطعه کد try/finally توسط کامپایلر جهت فراخوانی متد Dispose، تشکیل خواهد شد. بنابراین اگر بخواهیم متد UsingNewScope را توسط using statements پیشین بازنویسی کنیم، به یک چنین قطعه کدی خواهیم رسید که scope پس از using declarations، تا آخر متد ادامه پیدا میکند:
سؤال: آیا امکان محدود کردن میدان دید using declarations وجود دارد؟
پاسخ: بله. میتوان با تعریف یک {}، میدان دید متغیرهای ارجاعی توسط using declarations را محدود کرد:
در اینجا جائیکه {} بسته میشود، متغیر r1 از میدان دید خارج شده و بلافاصله Dispose خواهد شد.
سؤال: آیا using declarations تمام قابلیتهای using statements را ارائه میدهند؟
پاسخ: خیر. فرض کنید کلاس AResource از نوع IDisposable تعریف شدهاست:
و سپس متدی، وهلهای از این کلاس را باز میگرداند:
با استفاده از using statements، نوشتن چنین قطعه کدی بدون تعریف متغیری مجاز است:
اما اگر اینکار را توسط using declarations انجام دهیم، به چندین خطای کامپایلر خواهیم رسید:
علت اینجا است که برخلاف using statements، ذکر متغیرهای scope برای using declarations اجباری است. برای رفع آن میتوان از یک discard استفاده کرد:
مثالی از using declarations
تا پیش از C# 8.0، روش متداول کار با عبارات using به صورت زیر است و به آن استفاده از using statements گفته میشود:
class Program { static void UsingOld() { using (var file = new FileStream("input.txt", FileMode.Open)) using (var reader = new StreamReader(file)) { var s = reader.ReadToEnd(); // Do something with data } }
اکنون در C# 8.0 میتوان قطعه کد فوق را به کمک using declarations به صورت زیر خلاصه کرد:
class Program { static void UsingNew(string[] args) { using Stream file = new FileStream("input.txt", FileMode.Open); using StreamReader reader = new StreamReader(file); var s = reader.ReadToEnd(); // Do something with data }
میدان دید using declarations
پس از این تغییرات، سؤال مهمی که مطرح میشود این است: متغیرهایی که توسط using declaration تعریف میشوند، تا چه زمانی زنده نگه داشته میشوند. به عبارتی متد UsingOldScope آیا همانند متد UsingNewScope عمل میکند؟ آیا متغیر buffer آن همانند متد UsingOldScope خارج از میدان دید usingها قرار میگیرد؟
class Program { static void UsingNewScope() { string buffer = null; using Stream file = new FileStream("input.txt", FileMode.Open); using StreamReader reader = new StreamReader(file); buffer = reader.ReadToEnd(); // Do something with data buffer = null; } static void UsingOldScope(string[] args) { string buffer = null; using (var file = new FileStream("input.txt", FileMode.Open)) using (var reader = new StreamReader(file)) { buffer = reader.ReadToEnd(); } // Do something with data buffer = null; }
اما زمانیکه از using declarations استفاده میشود (مانند متد UsingNewScope)، دیگر این {} را نداریم. اینبار scope تعریف شده، تا «پایان متد» ادامه پیدا میکند و سپس متد Dispose اشیاء ارجاعی، فراخوانی میگردد. بدیهی است در اینجا نیز همانند قبل، همان قطعه کد try/finally توسط کامپایلر جهت فراخوانی متد Dispose، تشکیل خواهد شد. بنابراین اگر بخواهیم متد UsingNewScope را توسط using statements پیشین بازنویسی کنیم، به یک چنین قطعه کدی خواهیم رسید که scope پس از using declarations، تا آخر متد ادامه پیدا میکند:
string buffer = null; using (var file = new FileStream("input.txt", FileMode.Open)) { using (var reader = new StreamReader(file)) { buffer = reader.ReadToEnd(); buffer = null; } }
پاسخ: بله. میتوان با تعریف یک {}، میدان دید متغیرهای ارجاعی توسط using declarations را محدود کرد:
private static void UsingDeclarationWithScope() { { using var r1 = new AResource(); r1.UseIt(); } // r1 is disposed here! Console.WriteLine("r1 is already disposed"); }
سؤال: آیا using declarations تمام قابلیتهای using statements را ارائه میدهند؟
پاسخ: خیر. فرض کنید کلاس AResource از نوع IDisposable تعریف شدهاست:
public class AResource : IDisposable { public void UseIt() => Console.WriteLine(nameof(UseIt)); public void Dispose() => Console.WriteLine($"Dispose {nameof(AResource)}"); }
class Program { public static AResource GetTheResource() => new AResource();
using (GetTheResource()) { // do something here } // resource is disposed here
using GetTheResource(); // Compiler error
using var _ = GetTheResource(); // Works fine
مسیرراهها