۹ ویژگی تازه در C# 6 از ویدئویی از مدز ترگرسن که Langauge PM برای زبان سی شارپ هست، استخراج شدهاند.
در واقع مفاهیم بزرگ جدیدی به زبان سی شارپ در ورژن ۶ اضافه نشده، بلکه چند ویژگی کوچک تازه وجود دارند که به مرتب و خواناتر کردن کد کمک میکنند.
۱. پراپرتیهای خودکار که فقط Get دارند
قبلاً پراپرتیها حتماً باید getter و setter میداشتند اما الان میتوانید setter مشخص نکنید، در نتیجه پراپرتی شما فقط خواندنی است (بدون آن که آن را فقط خواندنی کنید) و در پشت صحنه مقادیر در فیلد متناظر آنها ذخیره میشوند.
ضمناً میتوانید پراپرتیها را در همان تعریف مقداردهی اولیه نمایید.
public class Point { // قبلاً public int X { get; set; } // الان public int Y { get; } = 7; }
۲. استفاده از اعضای static
قبلاً برای فراخوانی اعضای استاتیک یک کلاس باید نام آن را میآوردید اما الان با استفاده از using میتوانید از نام کلاس فاکتور بگیرید.
using static System.Math; .... // قبلاً var c = Math.Sqrt( X * X + Y * Y ); // الان var c = Sqrt( X * X + Y * Y );
این موضوع در مورد enumها هم برقرار است.
۳. الحاق (و قالب بندی) رشته
کد زیر را در نظر بگیرید. این روش مدتهاست که برای قالب بندی کد و درج متغیرها (و مقادیر) داخل رشتهها استفاده میشود.
return String.Format( "{0}, {1}", X, Y );
غیر از طولانی بودن کد، عیب بزرگ این روش این است که شماره گذاری مقادیر بسیار گیج کننده است خصوصاُ اگر تغییر یا جابجایی رخ دهد، به همین دلیل بسیار مستعد خطاست.
خب، روش جدید این مشکلات را حل کرده است:
return $"{X}, {Y}";
عبارت String.Format با علامت $ جایگزین شد و حتماً دقت کردید که متغیرها مستقیماً به جای شمارهها قرار گرفتهاند (چیزی شبیه به کدهای PHP).
بروزرسانی: در تغییر جدید علامت $ حذف شده و به جای آن قبل از } از یک \ استفاده شده است:
return "\{X}, \{Y}";
۴. متدهایی با بدنه تک عبارتی
اگر متد شما تنها یک خط کد دارد که عبارتی (مثلاً نتیجه محاسبهای) را برمیگرداند، چیزی شبیه به عبارتهای لامبدا، میتوانید از این ویژگی جدید استفاده کنید.
// قبلاً public int P(int a) { return a * a; } // الآن public int P(int a) => a * a;
این اتفاق برای متد get پراپرتیها هم افتاده است:
// قبلاً public int P { get { return a * a; } } // الآن public int P => a * a;
۵. مقداردهی اولیه با اندیس
بارها شده که از مقداردهی اولیه برای پراپرتیهای اشیاء استفاده کردهاید. اما اگر نیاز به اندیس داشته باشید چه خواهید کرد. حالا این ویژگی جدید را که برای آسان کردن این مورد اضافه شده ببینید.
// قبلاً var result = new JObject(); result["x"] = X; result["y"] = Y; // الآن var result = new JObject() { ["x"] = X, ["y"] = Y };
۶. عملگرهای شرطی null
این یکی هم استفاده زیادی دارد. بررسی null بودن (خصوصاً برای یک شئ قبل از استفاده از پراپرتیهای آن شئ) به شکل قابل قبولی خلاصه شده.
// قبلاً if (json != null && json["x"] != null && json["x"].Type == JTokenType.Ineger && json["y"] != null && json["y"].Type == JTokenType.Integer) { // some code }
در این کد ابتدا بررسی شده که متغیر json نال نباشد، سپس بررسی شده که اندیس x نال نباشد و بعد نوع اندیس x بررسی شده. همچنین نال نبودن اندیس y و نوع آن نیز مورد بررسی قرار گرفته است.
// الآن if (json != null && json["x"]?.Type == JTokenType.Integer && json["y"]?.Type == JTokenType.Integer) { // some code }
اینجا از عملگر .? استفاده شده است. این عملگر ابتدا نال نبودن عملوند سمت چپ خود را بررسی میکند و در صورت نال نبودن به قسمت سمت راست خواهد پرداخت. یعنی اگر سمت چپ نال بود کل عبارت نال است و اگر نبود عملگر . (نقطه (dot)) مانند گذشته عمل خواهد کرد.
عبارت انگلیسی مورد استفاده برای توضیح این عملگر را به خاطر ریتمش میآورم تا بهتر در خاطر بماند:
If null then null, if not then dot.
حالا به این قسمت توجه کنید. میتوان از عملگر ? دوبار در یک عبارت استفاده کرد. در نتیجه عبارات فوق به شکل زیر سادهتر میشوند:
if (json?["x"]?.Type == JTokenType.Integer && json?["y"]?.Type == JTokenType.Integer) { // some code }
عملگر ? در جلو json ابتدا چک میکند که سمت چپ عملگر (یعنی متغیر json) نال است یا نه. اگر بود کل عبارت null است و اگر نبود اندیس x بررسی میشود (یعنی اجرای سمت راست عملگر ادامه خواهد یافت).
یک کاربرد جالب این عملگر هنگام فراخوانی eventهاست. تصور کنید رویدادی را مانند زیر فراخوانی کنید:
OnChanged(this, args);
معمولاً قبل از این کار نال بودن آن را بررسی میکنیم:
if (OnChanged != null) { OnChanged(this, args); }
اما این شیوه به اصطلاح thread-safe نیست. اگر درست لحظه بعد از دستور if و بررسی نال بودن، یک ترد دیگر این رویداد را نال کند باز هم با استثنا مواجه خواهیم شد. یک راه این است که ابتدا یک کپی از آن بگیریم و نال بودن آن را بررسی و نهایتاً هم آن کپی را اجرا کنیم:
var onChanged = OnChanged; if (onChanged != null) { onChanged(this, args); }
اما این کد برای یک فراخوانی ساده خیلی طولانی است. راه حل آن خیلی ساده است. ضمن این که این روش جدید thread-safe هم هست.
OnChanged?.Invoke(this, args);
۷. عملگر nameof
فکر کنید کدی شبیه به قطعه کد زیر دارید.
public Point Add(Point point) { if (point == null) { throw new ArgumentNullException("point"); } }
میبینید که اسم یک عنصر برنامه داخل رشته مورد استفاده قرار گرفته است. اگر نام این عنصر تغییر کند، به احتمال زیاد تغییر آن در داخل رشتهها را فراموش خواهید کرد و چون این نام داخل رشته بوده خطایی هنگام کامپایل مشاهده نمیکنید. در ورژن جدید سی شارپ میتوانید به جای نوشتن مستقیم نام عنصر برنامه از عملگر nameof استفاده کنید:
throw new ArgumentNullException( nameof(point) );
۸. فیلترهای استثنا
این ویژگی قبلاً در #F و VB وجود داشت و حالا به #C هم اضافه شده است. اگر استثنایی رخ بدهد که منشأ دیگری داشته باشد و شما آن را catch کنید و سپس دوباره throw کنید اطلاعات از مبدأ اصلی در مورد استثنا را از دست خواهید داد. برای حل این مشکل میتوانید استثناهایی را که catch میکنید فیلتر نمایید. به قطعه کد زیر توجه کنید:
catch (ConfigurationException e) when (e.IsSevere) { ... }
بروزرسانی: کلمه when به if تغییر پیدا کرده:
... e) if (e.IsSevere)
۹. await در catch و finally
ویژگی دیگری که اضافه شده امکان استفاده از await در بلاکهای catch و finally است.
catch (ConfigurationException e) when (e.IsSevere) { await LogAsync(e); } finally { await CloseAsync(); }
منبع: http://goo.gl/TQ0ASd
البته در فاصله نوشتن این پست، ظاهرا تغییرات کوچکی در فیلم داده شده !!!
دیدگاهتان را بنویسید