Menu

Switch case ב-C#: פקודת switch עם case, break, default וכמה ערכים

איך פקודת switch עובדת ב-C#: switch על ערכי int, string, char ו-enum, למה כל case צריך break (שגיאה CS0163), תוויות case מרובות לכמה ערכים, goto case, default, תלות באותיות גדולות וקטנות במחרוזות, ותוויות case עם תבניות ו-when.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

פקודת switch משווה ערך אחד לרשימה של תוויות case קבועות ומריצה את הקטע שמתאים. ב-C#, כל קטע חייב להסתיים ב-break (או בפקודה אחרת שיוצאת ממנו), כך ש-case אחד לעולם לא יכול לרוץ בשקט לתוך הבא.

פלט:

200: OK
302: redirect
404: not found
500: unhandled status

הערך שבסוגריים מחושב פעם אחת ומושווה לכל תווית. default רץ כששום דבר לא מתאים; הוא אופציונלי, והוא יכול להופיע בכל מקום ברשימה, אם כי בדרך כלל הוא בא אחרון. אם אין התאמה ואין default, כל ה-switch לא עושה כלום.

כל קטע צריך break

ב-C, C++, Java ו-JavaScript, שכחה של break גורמת לביצוע לגלוש ל-case הבא. 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:').

כמה ערכים ב-case אחד

תוויות שאין ביניהן פקודות חולקות את הקטע שמתחתיהן. זה הסוג היחיד של נפילה ש-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 על מחרוזת

מחרוזות הן ערך ה-switch הנפוץ ביותר אחרי מספרים שלמים. ההשוואה סידורית ותלויה באותיות גדולות וקטנות, אז נרמלו את הקלט לפני ה-switch:

פלט:

Starting the server
Stopping the server
Server is running
Unknown command: restart
Unknown command: (none)

בלי ToLowerInvariant, "STOP" היה מגיע ל-default. מותר לבצע switch על ערך null: הוא לא מתאים לאף קבוע מחרוזת ונופל ל-default, כך שה-switch עצמו לעולם לא זורק חריגה.

switch על enum

בשביל זה 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 מכסה כל איבר של ה-enum, ומשתנה enum יכול להחזיק כל מספר שלם של טיפוס הבסיס שלו ((OrderStatus)42 חוקי). ה-default שזורק חריגה הופך case שנשכח לכישלון מיידי וברור במקום פעולה שקטה שלא עושה כלום.

goto case ו-goto default

כש-case אחד באמת צריך להמשיך לתוך אחר, C# מחייבת אתכם לכתוב את הקפיצה:

פלט:

admin:
  manage users
  edit posts
  read posts
editor:
  edit posts
  read posts
guest:
  read posts

goto case מקבלת קבוע שחייב להתאים לאחת התוויות באותו switch. זה נדיר בקוד אמיתי: התנהגות משותפת בדרך כלל ברורה יותר כמתודה שכמה מקרים קוראים לה. ובכל זאת, זו התשובה לשאלה "איך עושים fall through ב-C#".

משתנים בתוך מקרים

כל בלוק ה-switch הוא טווח (scope) אחד, כך ששני מקרים לא יכולים להצהיר על משתנה עם אותו שם:

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 בתוך case יוצאת מה-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 הראשון שמתאים מנצח, והקומפיילר מדווח על שגיאה כשאי אפשר להגיע ל-case כי case קודם כבר מכסה אותו (הצבת case int n: מעל case int n when n < 0: נכשלת). פסוקית ה-when עובדת גם על מקרים קבועים: case 0 when isAdmin:. C# 9 הוסיפה תבניות יחס ותבניות לוגיות, כך ש-case יכול להיכתב 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 מכסה את התחביר, התבניות וכללי הכיסוי המלא שלו.

על מה אפשר לעשות 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, וזה כולל גם את הקטע האחרון.

איך מטפלים בכמה ערכים ב-case אחד של switch ב-C#?

ערמו את התוויות בלי שום דבר ביניהן: case "sat": case "sun": Console.WriteLine("weekend"); break;. תוויות case ריקות יכולות ליפול לתווית הבאה; רק קטע שמכיל פקודות חייב להסתיים ב-break. ב-C# 9 ומעלה, case עם תבנית יכול גם לכתוב case 1 or 2 or 3:.

האם switch על מחרוזת ב-C# תלוי באותיות גדולות וקטנות?

כן. מקרי מחרוזת מושווים בשוויון סידורי (ordinal) שתלוי באותיות גדולות וקטנות, כך ש-"Yes" לא מתאים ל-case "yes":. נרמלו את הערך קודם עם switch (input.Trim().ToLowerInvariant()). מחרוזת null לא מתאימה לאף case קבוע ועוברת ל-default.

האם switch ב-C# יכול ליפול (fall through) כמו ב-C או ב-Java?

לא באופן מרומז. כשרוצים ש-case אחד ימשיך לתוך אחר, כתבו זאת במפורש עם 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

ללמוד תכנות עם Coddy

להתחיל