در C# 11، افزونهای به switch expressionها اضافه شدهاست که امکان بررسی توالی مقادیر آرایهها و مجموعهها را نیز میدهد که به آن list expressions هم میگویند. List Patterns امکان بررسی شکل یک لیست و یا آرایه را ممکن میکنند. برای مثال اگر نیاز است بررسی کنیم که آیا مجموعهای با یک مقدار خاص، شروع میشود، پایان مییابد و یا حاوی آن است، List Patterns مفید واقع خواهند شد. در اینجا List Patterns، با [] مشخص میشوند و در بین []ها، توالی مقادیری را که قرار است با اعضای مجموعهی مشخص شده، انطباق داده شوند، مشخص میکنیم. این افزونه به همراه ویژگی slice pattern نیز هست که امکان انطباق با صفر و یا چند المان یک مجموعه را میسر میکند. در این حالت از دو نقطه برای نمایش آن در بین []ها استفاده میشود. برای مثال الگوی زیر:
با تمام آرایههای زیر انطباق دارد:
int[] arr1 = { 1, 2, 10 };
int[] arr2 = { 1, 2, 5, 10 };
int[] arr3 = { 1, 2, 5, 6, 7, 8, 9, 10 };
بررسی چند مثال جهت آشنایی با مفهوم List Patterns
ابتدا مجموعهی زیر را در نظر بگیرید:
int[] collection = { 1, 2, 3, 4 };
الف) روش انطباق با یک توالی مشخص
Console.WriteLine(collection is [1, 2, 3, 4]); // True
Console.WriteLine(collection is [1, 2, 4]); // False
توالی مشخص شدهی در الگوی اول، دقیقا با توالی عناصر آرایه انطباق دارد. اما در حالت دوم، چون توالی اعداد الگوی مشخص شده، با توالی اعداد آرایه یکی نیست، انطباقی رخ ندادهاست.
ب) امکان استفاده از discard و همچنین لیستی از عناصر
Console.WriteLine(collection is [_, 2, _, 4]); // True
Console.WriteLine(collection is [.., 3, _]); // True
- اگر نیاز به صرفنظر کردن از عناصر خاصی در یک توالی بود، میتوان از discard و یا همان _ استفاده کرد؛ مانند الگوی اول. الگوی اول به معنای نیاز به انطباق با چهار عدد است که حتما باید دومین و چهارمین آنها اعداد 2 و 4 باشند؛ اما مقدار اولین و سومین آنها، مهم نیست.
- الگوی دوم به معنای تعریف یک توالی نامشخص، اما خاتمه یافتهای با عنصر 3 است و سپس صرفنظر کردن از آخرین عنصر آرایه.
در مثال زیر، الگوی انطباق با مجموعهای که حداقل دو عضو دلخواهی را دارد، مشاهده میکنید:
if (new[] { 6, 7, 8 } is [_, _, ..])
{
Console.WriteLine($"collection with at least two items");
}
و الگوی انطباق با مجموعهای که اولین و آخرین عضو آن صفر هستند:
if (new[] { 0, 42, 42, 0 } is [0, .., 0])
{
Console.WriteLine($"collection with first and last element equal to 0");
}
ج) امکان تعریف اعمال منطقی Console.WriteLine(collection is [_, >= 2, _, _]); // True
بر اساس این الگو، هر مجموعهی چهارتایی که عنصر دوم آن، بزرگتر و یا مساوی 2 باشد، معتبر شناخته میشود؛ صرفنظر از مقدار سایر عناصر آن.
در مثال زیر، الگوی انطباق با مجموعهای را که اولین عضو آن یک عدد مثبت است، مشاهده میکنید:
if (new[] { 9, -1, -2 } is [> 0, ..])
{
Console.WriteLine($"collection with positive first element");
}
و یا الگوی انطباق با مجموعهای که دومین عضو آن، یکی از دو عدد 42 و منهای 42 میتواند باشد:
if (new[] { 1, 42, 0 } is [_, 42 or -42, ..])
{
Console.WriteLine($"collection with second element equal to 42 or -42");
}
یک مثال دیگر: بررسی نحوهی عملکرد List Patterns namespace CS11Tests;
public static class ListPatternsMatching
{
public static void Test()
{
Console.WriteLine(CheckSwitch(new[] { 1, 2, 10 })); // prints 1
Console.WriteLine(CheckSwitch(new[] { 1, 2, 7, 3, 3, 10 })); // prints 1
Console.WriteLine(CheckSwitch(new[] { 1, 2 })); // prints 2
Console.WriteLine(CheckSwitch(new[] { 1, 3 })); // prints 3
Console.WriteLine(CheckSwitch(new[] { 1, 3, 5 })); // prints 4
Console.WriteLine(CheckSwitch(new[] { 2, 5, 6, 7 })); // prints 50
}
public static int CheckSwitch(int[] values)
=> values switch
{
[1, 2, .., 10] => 1,
[1, 2] => 2,
[1, _] => 3,
[1, ..] => 4,
[..] => 50
};
}
توضیحات:
- اولین الگوی تعریف شدهی در متد CheckSwitch، به معنای انطباق با هر توالی است که با 1 و 2 شروع میشود و سپس میتواند شامل هر نوع توالی دلخواهی باشد (صرفنظر از مقدار و یا ترتیب این مقادیر) و در نهایت با عدد 10 خاتمه پیدا میکند.
- دومین الگوی تعریف شده، تنها یک آرایهی دو عضوی با مقادیر مشخص 1 و 2 را میپذیرد.
- توالی قابل انطباق با سومین الگوی تعریف شده، از دو عضو تشکیل میشود. اولین عضو آن حتما باید 1 باشد و مقدار دومین عضو آن مهم نیست.
- توالی قابل انطباق با چهارمین الگوی تعریف شده، از یک یا چند عضو دلخواه تشکیل میشود که اولین عضو آن حتما باید عدد 1 باشد.
- هر توالی تعریف شدهای با پنجمین الگوی تعریف شده، انطباق پیدا میکند.
امکان ترکیب list pattern matching و object pattern matching
در مثالهای زیر، نمونهای از ترکیب list pattern matching و object pattern matching را جهت ساخت شرطهای پیچیدهای، مشاهده میکنید:
if (new[] { 1, 2, 3 } is [var first, _, _])
{
Console.WriteLine($"three item collection with first item {first}");
}
if (new[] { 4, 5, 6 } is [_, var second, _])
{
Console.WriteLine($"three item collection with second item {second}");
}
این الگو که var pattern هم نامیده میشود، به همراه ذکر var و نام یک متغیر است. در این حالت کار الگو، دریافت مقدار واقع شدهی در آن موقعیت خاص است.
نمونه مثالی از این قابلیت جهت جدا سازی اجزای یک URL:
var uri = new Uri("http://www.mysite.com/categories/category-a/sub-categories/sub-category-a.html");
var result = uri.Segments switch
{
["/"] => "Root",
[_, var single] => single,
[_, .. string[] entries, _] => string.Join(" > ", entries)
};
سایر نوعهایی که توسط List patterns قابل بررسی هستند
List patterns تنها با آرایهها و لیستها کار نمیکنند. بلکه میتوان از آنها با هر نوعی که به همراه تعریف indexerها و یا خواص Length و Count است نیز استفاده کرد. اگر نیاز به استفاده از Slice patterns بود، این الگو با نوعهایی کار میکند که دارای indexer هایی با آرگومانهایی از نوع Range است و یا به همراه متد Slice دارای دو آرگومان Int است. برای مثال رشتهها نیز در اینجا قابل بررسی هستند.