یکی از ویژگیهای زبان VB، شباهت بیش از اندازهی آن به زبان انگلیسی است. برای مثال در این زبان با استفاده از not و and:
If Not a And b Then
...
Else
...
EndIf
میتوان ifهای خواناتری را نسبت به #C ایجاد کرد:
if(!(a) && b)
{
...
}
else
{
}
در ادامه خواهیم دید که چگونه C# 9.0، این آرزوی دیرین را برآورده میکند! البته مایکروسافت در جای دیگری هم عنوان کردهاست که زبان VB را
دیگر پیگیری نمیکند و تغییر خاصی را در آن شاهد نخواهید بود. شاید به همین دلیل و جذب برنامه نویسهای VB به #C، یک چنین تغییراتی رخ دادهاند!
معرفی واژهی کلیدی جدید not در C# 9.0
در ابتدا اینترفیس نمونهای را به همراه دو کلاس مشتق شدهی از آن درنظر بگیرید:
public interface ICommand
{
}
public class Command1 : ICommand
{
}
public class Command2 : ICommand
{
}
اکنون اگر وهلهای از Command1 را ایجاد کرده و بخواهیم بررسی کنیم که آیا از نوع کلاس Command2 هست یا خیر، با استفاده از pattern matching و واژهی کلیدی if میتوان به صورت زیر عمل کرد:
ICommand command = new Command1();
if (!(command is Command2))
{
}
در C# 9.0، برای خواناتر کردن یک چنین بررسیهایی، میتوان از pattern matching بهبود یافتهی آن و واژهی کلیدی جدید not نیز استفاده کرد:
if (command is not Command2)
{
}
معرفی واژههای کلیدی جدید and و or در C# 9.0
واژههای کلیدی جدید and و or نیز درک و نوشتن عبارات pattern matching را بسیار ساده میکنند. برای نمونه قطعه کد متداول زیر را درنظر بگیرید:
if ((command is ICommand) && !(command is Command2))
{
}
اکنون در C# 9.0 با استفاده از واژههای کلیدی جدید and، or و not، میتوان قطعه کد فوق را بسیار ساده کرد:
if (command is ICommand and not Command2)
{
}
نه تنها این قطعه کد سادهتر شدهاست، بلکه خوانایی آن افزایش یافتهاست و مانند یک سطر نوشته شدهی به زبان انگلیسی به نظر میرسد. همچنین در این حالت نیازی هم به تکرار command، در هر بار مقایسه نیست.
و یا حتی در اینجا در صورت نیاز میتوان از واژهی کلیدی جدید or نیز استفاده کرد:
if (command is Command1 or Command2)
{
}
امکان اعمال واژههای کلیدی جدید and، or و not به سایر نوعها نیز وجود دارند
تا اینجا مثالهایی را که بررسی کردیم، در مورد بررسی نوع اشیاء بود. اما میتوان این واژههای کلیدی جدید در C# 9.0 را به هر نوع ممکنی نیز اعمال کرد. برای نمونه، مثال سادهی زیر را که در مورد بررسی اعداد است، درنظر بگیرید:
var number = new Random().Next(1, 10);
if (number > 2 && number < 8)
{
}
اکنون در C# 9.0 و با استفاده از امکانات جدید pattern matching آن میتوان شرط متداول فوق را به صورت زیر ساده کرد:
if (number is > 2 and < 8)
{
}
در اینجا تنها یکبار نیاز به ذکر number است و از واژههای کلیدی is و and استفاده شدهاست.
یک مثال دیگر: متد زیر را در نظربگیرید که با استفاده از && و || متداول #C نوشته شدهاست:
public static bool IsLetterOrSeparator(char c) =>
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '.' || c == ',';
روش ارائهی C# 9.0 ای آن به صورت زیر است:
public static bool IsLetterOrSeparator(char c) =>
c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ',';
امکان اعمال واژههای کلیدی جدید and، or و not به switchها نیز وجود دارد
برای نمونه قطعه کد if/else دار متداول زیر را درنظر بگیرید که قابلیت تبدیل به یک سوئیچ را نیز دارد:
var number = new Random().Next(1, 10);
if (number <= 0)
{
Console.WriteLine("Less than or equal to 0");
}
else if (number > 0 && number <= 10)
{
Console.WriteLine("More than 0 but less than or equal to 10");
}
else
{
Console.WriteLine("More than 10");
}
اگر بخواهیم همین قطعه کد را به کمک واژههای کلیدی جدید C# 9.0 و pattern matching بهبود یافتهی آن تبدیل به یک سوئیچ کنیم، به قطعه کد زیر خواهیم رسید:
// C#9.0
switch (number)
{
case <= 0:
Console.WriteLine("Less than or equal to 0");
break;
case > 0 and <= 10:
Console.WriteLine("More than 0 but less than or equal to 10");
break;
default:
Console.WriteLine("More than 10");
break;
}
تا پیش از C# 7.0، سوئیچهای #C امکان بررسی بازهای از مقادیر را نداشتند. از آن زمان با معرفی pattern matching، چنین محدودیتی برطرف شد و اکنون میتوان syntax قدیمی آنرا توسط C# 9.0، بسیار خلاصهتر کرد. در ذیل، معادل قطعه کد فوق را بر اساس امکانات C# 7.0 مشاهده میکنید که خوانایی کمتری را داشته و حجم کد نویسی بیشتری را دارد:
// C#7.0
switch (number)
{
case int value when value <= 0:
Console.WriteLine("Less than or equal to 0");
break;
case int value when value > 0 && value <= 10:
Console.WriteLine("More than 0 but less than or equal to 10");
break;
default:
Console.WriteLine("More than 10");
break;
}
و یا حتی میتوان سوئیچ C# 9.0 را توسط switch expression بهبود یافتهی C# 8.0 نیز به شکل زیر بازنویسی کرد:
var message = number switch
{
<= 0 => "Less than or equal to 0",
> 0 and <= 10 => "More than 0 but less than or equal to 10",
_ => "More than 10"
};
انواع pattern matchingهای اضافه شدهی به C# 9.0
در این مطلب سعی شد مفاهیم pattern matching اضافه شدهی به C# 9.0، ذیل عنوان واژههای کلیدی جدید آن بحث شوند؛ اما هر کدام دارای نامهای خاصی هم هستند:
الف) relational patterns: امکان استفادهی از <, >, <= and >= را در الگوها میسر میکنند. مانند نمونههای سوئیچی که نوشته شد.
ب) logical patterns: امکان استفادهی از واژههای کلیدی and، or و not را در الگوها ممکن میکنند.
ج) not pattern: امکان استفادهی از واژهی کلیدی not را در عبارات if میسر میکند.
د) Simple type pattern: در مثالهای زیر، پس از انطباق با یک الگو، کاری با متغیر یا شیء مرتبط نداریم. در نگارشهای قبلی برای صرفنظر کردن از آن، ذکر _ ضروری بود؛ اما در C#9.0 میتوان آنرا نیز ذکر نکرد:
private static int GetDiscount(Product p) => p switch
{
Food => 0, // Food _ => 0 before C# 9
Book b => 75, // Book b _ => 75 before C# 9
_ => 25
};