Menu
flag Ar iconالعربيةdown icon

جملة switch في C#: case وbreak وdefault والحالات المتعددة

كيف تعمل جملة switch في C#: التفرّع على قيم int وstring وchar وenum، ولماذا تحتاج كل حالة إلى break (الخطأ CS0163)، وتكديس عناوين case لعدة قيم، وgoto case، وdefault، وحساسية حالة الأحرف في النصوص، وعناوين case النمطية مع when.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

تقارن جملة 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" };. استخدم التعبير حين لا يفعل كل فرع سوى حساب نتيجة.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن