تقارن جملة switch قيمة واحدة بقائمة من عناوين case الثابتة وتنفّذ القسم المطابق. في C# يجب أن ينتهي كل قسم بـ break (أو بعبارة أخرى تغادره)، فلا يمكن لحالة أن تنزلق بصمت إلى التالية.
المخرجات:
200: OK
302: redirect
404: not found
500: unhandled status
تُقيَّم القيمة بين القوسين مرة واحدة وتُقارن بكل عنوان. يُنفَّذ default حين لا يطابق شيء؛ وهو اختياري، ويمكن أن يظهر في أي مكان من القائمة، مع أنه يأتي عادة في النهاية. إن لم يوجد تطابق ولا default فلا تفعل جملة switch كلها شيئًا.
كل قسم يحتاج إلى break
في C وC++ وJava وJavaScript يجعل نسيان break التنفيذ ينزلق إلى الحالة التالية. أما C# فتحوّل هذا الخطأ إلى خطأ ترجمة:
switch (level)
{
case 1:
Console.WriteLine("read");
// error CS0163: Control cannot fall through from one case label ('case 1:') to another
case 2:
Console.WriteLine("write");
break;
}
القاعدة أن نهاية قائمة عبارات القسم يجب ألا تكون قابلة للوصول. break هي الطريقة المعتادة لتحقيق ذلك، لكن أي شيء يغادر القسم يعمل:
- تغادر
returnالدالة كلها، وهي غالبًا الشكل الأنظف داخل دالة مساعدة صغيرة. - ترمي
throwاستثناءً لقيمة يجب ألا تحدث أبدًا. - تقفز
continueإلى التكرار التالي حين تكونswitchداخل حلقة. - تقفز
goto caseوgoto defaultإلى قسم آخر عن قصد.
القسم الأخير ليس مستثنى. يفشل default: في الأسفل دون break بالخطأ CS8070، Control cannot fall out of switch from final case label ('default:').
عدة قيم في حالة واحدة
العناوين التي لا عبارات بينها تتشارك القسم الذي تحتها. هذا هو النوع الوحيد من الانزلاق الذي تسمح به C#، لأن العنوان الفارغ لا يمكن أن يخفي أي شيفرة:
المخرجات:
'O' is a vowel
'k' is a consonant or symbol
' ' is a space
'7' is a digit
كل قسم هنا ينتهي بـ return، فلا حاجة إلى break (فـ break بعد return ستكون شيفرة لا يمكن الوصول إليها). عنوانان بالقيمة نفسها خطأ، CS0152 The switch statement contains multiple cases with the label value '1'، ويجب أن يكون كل عنوان ثابتًا وقت الترجمة: متغيّر في case يفشل برسالة "a constant value is expected".
switch على نص
النصوص أشيع قيمة تفرّع بعد الأعداد الصحيحة. المقارنة ترتيبية وحساسة لحالة الأحرف، فوحّد المدخلات قبل التفرّع:
المخرجات:
Starting the server
Stopping the server
Server is running
Unknown command: restart
Unknown command: (none)
دون ToLowerInvariant كانت "STOP" ستصل إلى default. التفرّع على قيمة null مسموح: لا تطابق أي ثابت نصي وتذهب إلى default، فلا ترمي جملة switch نفسها استثناءً أبدًا.
switch على تعداد
التعدادات هي ما صُنعت له switch: مجموعة مغلقة من القيم المسمّاة.
المخرجات:
Pending: wait for payment
Paid: pack and ship
Shipped: track the parcel
Delivered: nothing, order is closed
Cancelled: nothing, order is closed
ArgumentOutOfRangeException for value 42
لا يتحقق المترجم أن جملة switch تغطي كل أعضاء التعداد، ويمكن لمتغيّر التعداد أن يحمل أي عدد صحيح من نوعه الأساسي ((OrderStatus)42 صحيحة). والـ default الذي يرمي استثناءً يحوّل الحالة المنسية إلى فشل فوري واضح بدل عدم فعل شيء بصمت.
goto case وgoto default
حين يجب فعلًا أن تستمر حالة في أخرى، تجعلك C# تكتب القفزة:
المخرجات:
admin:
manage users
edit posts
read posts
editor:
edit posts
read posts
guest:
read posts
تأخذ goto case ثابتًا يجب أن يطابق أحد العناوين في جملة switch نفسها. وهي نادرة في الشيفرة الحقيقية: السلوك المشترك يكون عادة أوضح كدالة تستدعيها عدة حالات. لكنها ما زالت الإجابة عن سؤال "كيف أنزلق في C#".
المتغيّرات داخل الحالات
كتلة switch كلها نطاق واحد، فلا يمكن لحالتين التصريح بمتغيّر بالاسم نفسه:
switch (shape)
{
case "square":
int area = side * side;
break;
case "rectangle":
int area = width * height; // error CS0128: A local variable or function named 'area' is already defined in this scope
break;
}
ضع جسم كل قسم بين أقواس معقوصة لتمنحه نطاقًا خاصًا به: case "square": { int area = side * side; ... break; }.
break داخل حلقة
تغادر break في حالة ما جملة switch، لا الحلقة المحيطة بها. أما continue فتفعل العكس: switch ليست حلقة، فتذهب continue إلى التكرار التالي للحلقة.
المخرجات:
end marker found
Total: 134
استمرت الحلقة بعد "end" وأضافت 99. لإيقاف الحلقة من داخل switch اضبط علامة واختبرها بعد switch، أو انقل الحلقة إلى دالة واستخدم return. تقارن صفحة break وcontinue بين الخيارات.
عناوين case النمطية وwhen
منذ C# 7.0 يمكن لعنوان case أن يكون نمطًا بدل ثابت: يمكنه اختبار نوع القيمة وإضافة شرط when. هذا الشكل شائع في شيفرة C# الحديثة:
static string Describe(object value)
{
switch (value)
{
case null:
return "nothing";
case int n when n < 0:
return $"negative int {n}";
case int n:
return $"int {n}";
case string s when s.Length == 0:
return "empty string";
case string s:
return $"string \"{s}\"";
default:
return $"other: {value.GetType().Name}";
}
}
مع الأنماط يهمّ الترتيب: أول حالة مطابقة تفوز، ويبلّغ المترجم عن خطأ حين لا يمكن الوصول إلى حالة أبدًا لأن حالة سابقة تغطيها أصلًا (وضع case int n: فوق case int n when n < 0: يفشل). ويعمل البند when أيضًا مع الحالات الثابتة: case 0 when isAdmin:. أضافت C# 9 الأنماط العلائقية والمنطقية، فيمكن للحالة أن تُقرأ case >= 90: أو case 'a' or 'e' or 'i':.
في C# 7 دون أنماط يكون التفرّع نفسه بحسب النوع سلسلة if مع نمط النوع is:
المخرجات:
negative int -3
int 12
empty string
string "hi"
other: Decimal
nothing
حين لا يفعل كل فرع من switch سوى حساب قيمة يكون تعبير switch أقصر أيضًا: var grade = score switch { >= 90 => "A", >= 80 => "B", _ => "C" };. تغطي صفحة تعبير switch صياغته وأنماطه وقواعد الشمول.
ما الذي يمكنك التفرّع عليه
| نوع القيمة | حالات ثابتة | ملاحظات |
|---|---|---|
int وlong وbyte وسائر الأعداد الصحيحة | نعم | الحالة التقليدية |
char | نعم | case 'a': |
string | نعم | ترتيبية، حساسة لحالة الأحرف، null تذهب إلى default |
bool | نعم | مسموح، لكن if أوضح |
أي enum | نعم | لا فحص للشمول |
double وdecimal | منذ C# 7 | ثوابت فقط؛ النطاقات تحتاج إلى الأنماط العلائقية في C# 9 |
| أي نوع آخر | منذ C# 7 | عبر أنماط النوع، case Circle c: |
الأسئلة الشائعة
هل break إلزامية في switch في C#؟
يجب أن ينتهي كل قسم case بعبارة تغادره: عادة break، لكن return وthrow وcontinue (داخل حلقة) وgoto case تُحسب أيضًا. الانزلاق من نهاية قسم إلى القسم التالي خطأ ترجمة، CS0163 Control cannot fall through from one case label ('case 1:') to another، ويشمل ذلك القسم الأخير.
كيف أعالج عدة قيم في حالة switch واحدة في C#؟
كدّس العناوين دون شيء بينها: case "sat": case "sun": Console.WriteLine("weekend"); break;. العناوين الفارغة يمكنها الانزلاق إلى العنوان التالي؛ ولا يجب أن ينتهي بـ break إلا القسم الذي يحتوي على عبارات. في C# 9 وما بعده يمكن لحالة نمطية أيضًا أن تقول case 1 or 2 or 3:.
هل switch على نص في C# حساسة لحالة الأحرف؟
نعم. تُقارن حالات النصوص بمساواة ترتيبية حساسة لحالة الأحرف، فلا تطابق "Yes" الحالة case "yes":. وحّد القيمة أولًا بـ switch (input.Trim().ToLowerInvariant()). والنص null لا يطابق أي حالة ثابتة ويذهب إلى default.
هل يمكن لـ switch في C# أن تنزلق كما في C أو Java؟
ليس ضمنيًا. حين تريد أن تستمر حالة في أخرى قل ذلك صراحة بـ goto case <value>; أو goto default;. هذا يجعل كل انزلاق ظاهرًا في الشيفرة، ولهذا تمنع C# النسخة الصامتة.
ما الفرق بين جملة switch وتعبير switch في C#؟
تنفّذ جملة switch عبارات وتحتاج إلى case وbreak وdefault. أما تعبير switch (C# 8 وما بعده) فينتج قيمة: var label = n switch { 0 => "zero", > 0 => "positive", _ => "negative" };. استخدم التعبير حين لا يفعل كل فرع سوى حساب نتيجة.