Menu

if else ב-C#: שרשראות else if, תנאים וטעויות נפוצות

איך עובדים if, else if ו-else ב-C#: למה תנאים חייבים להיות bool, שילוב בדיקות עם &&, || ו-!, מתי סוגריים מסולסלים חשובים, guard clauses במקום קינון עמוק, והבאגים של = מול == ושל נקודה-פסיק מיותרת.

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

פקודת if מריצה בלוק קוד רק כשתנאי מתקיים. else if מוסיף עוד בדיקות, ו-else תופס את כל מה שהבדיקות לא תפסו.

פלט:

Order 120: shipping 0
Order 75.50: shipping 4.99
Order 20: shipping 9.99

התנאים נבדקים מלמעלה למטה והראשון שמתקיים מנצח. הזמנה של 120 מתאימה ל->= 100 ואף פעם לא מגיעה לבדיקה >= 50, ולכן התנאי הספציפי ביותר בא ראשון. else if היא לא מילת מפתח נפרדת: זה else שהגוף שלו הוא if נוסף, ולכן אין elseif או elif ב-C#.

תנאים חייבים להיות bool

C# אף פעם לא מתייחסת למספר, למחרוזת או לאובייקט כ-true או כ-false. הביטוי שבסוגריים חייב להיות מטיפוס bool:

int count = 3;
if (count)          // error CS0029: Cannot implicitly convert type 'int' to 'bool'
if (count > 0)      // correct
if (name)           // error: a string is not a bool either
if (name != null)   // correct

זה מסלק משפחה שלמה של באגים שקיימים ב-C וב-JavaScript, שבהן 0, "" ו-null נחשבים בשקט לשקר. המחיר הוא שכותבים את ההשוואה במפורש בכל פעם, וזה גם הופך את הכוונה לגלויה לקורא הבא.

שילוב תנאים עם &&, || ו-!

&& (וגם), || (או) ו-! (לא) משלבים בדיקות בוליאניות. && ו-|| מבצעים הערכה מקוצרת (short-circuit): הצד הימני רץ רק אם הצד השמאלי עוד לא הכריע את התשובה.

פלט:

maya: welcome
invalid or banned account
invalid or banned account
omar: age 9 rejected
invalid or banned account

הקריאה עם null בטוחה בזכות ההערכה המקוצרת: ברגע ש-username != null שקרי, username.Length לא מחושב אף פעם, ולכן אין NullReferenceException. החליפו את הסדר ל-username.Length >= 3 && username != null ואותה קריאה קורסת.

ל-&& יש קדימות גבוהה יותר מ-||, ולכן a || b && c פירושו a || (b && c). הוסיפו סוגריים בכל פעם שמערבבים את השניים; הקומפיילר לא צריך אותם, אבל הקוראים כן. גם & ו-| בתו אחד עובדים על bool, אבל הם תמיד מחשבים את שני הצדדים. השתמשו בהם רק כשלצד הימני יש תופעת לוואי שחייבת לקרות.

סוגריים מסולסלים וכלל הפקודה האחת

סוגריים מסולסלים הם אופציונליים כשענף מכיל פקודה אחת. בלעדיהם, רק הפקודה הבאה שייכת ל-if, לא משנה מה ההזחה אומרת:

פלט:

Reorder email sent
Stock: 12

"Reorder email sent" מודפס למרות שהמלאי תקין: ה-WriteLine השני נמצא מחוץ ל-if, למרות ההזחה. שומר של שורה אחת כמו if (x == null) return; בסדר גם בלי סוגריים מסולסלים; כל דבר שעלול לקבל שורה שנייה צריך אותם.

באג קשור הוא נקודה-פסיק מיד אחרי התנאי. if (stock < 5); מסיים את ה-if בפקודה ריקה, והבלוק שבא אחריו רץ בלי תנאי. הקומפיילר מסמן את זה באזהרה CS0642, Possible mistaken empty statement, ששווה להתייחס אליה כשגיאה.

= מול == בתנאי

= מבצע השמה, == משווה. ברוב הטיפוסים, כתיבה של = בטעות לא מתקמפלת, כי התוצאה של השמה היא הערך שהושם ו-int הוא לא bool:

int score = 10;
if (score = 100) { }   // error CS0029: Cannot implicitly convert type 'int' to 'bool'

עם משתנה bool ההשמה עצמה היא bool, ולכן שגיאת ההקלדה מתקמפלת:

פלט:

Access granted
isAdmin is now True

התנאי דרס את isAdmin ואז בדק את הערך החדש. הקומפיילר מזהיר (CS0665, השמה בביטוי תנאי היא תמיד קבועה), אבל הבנייה עדיין מצליחה. עבור bool, וותרו על ההשוואה לגמרי: if (isAdmin) ו-if (!isAdmin) קריאים יותר ואי אפשר להקליד אותם לא נכון בצורה הזו.

if מקונן מול guard clauses

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

פלט:

ordered 2 x keyboard
error: no product
error: quantity must be positive
error: insufficient balance

הגרסה המקוננת של אותה מתודה הייתה כוללת שלוש רמות של if, עם העבודה האמיתית בבלוק הפנימי ביותר ושלושה ענפי else שמתפרקים בתחתית. עם guard clauses, כל כלל יושב ליד הודעת השגיאה שלו והשורה האחרונה היא המקרה הרגיל. אותו רעיון עובד בתוך לולאות עם continue.

הצהרה על משתנים בתוך התנאי

תנאי יכול להצהיר על משתנה שנמצא בטווח בתוך ה-if. שתי הצורות הנפוצות הן out var ממתודת TryParse ותבנית הטיפוס עם is:

פלט:

42: positive number 42
abc: not a number
-7: number -7, not positive
string of length 5

TryParse מחזירה false במקום לזרוק חריגה על קלט שגוי, ולכן היא מתאימה באופן טבעי ל-if. העמוד על המרת טיפוסים מכסה את מתודות הפענוח בפירוט.

מתי להשתמש במשהו אחר

  • בחירה של אחד משני ערכים: אופרטור התנאי condition ? a : b קצר יותר מ-if שמבצע השמה בשני הענפים.
  • הרבה ענפים על ערך אחד: פקודת switch משווה ערך מול מקרים קבועים, וקל יותר לסרוק אותה מאשר עשר שורות של else if.
  • מיפוי של ערך לתוצאה: חיפוש ב-Dictionary מחליף שרשרת ארוכה כשהענפים שונים רק בנתונים.

שאלות נפוצות

איך כותבים else if ב-C#?

כתבו else if כשתי מילים: if (a) { ... } else if (b) { ... } else { ... }. התנאים נבדקים מלמעלה למטה ורק הענף הראשון שמתקיים רץ, ולכן שימו את הבדיקה הספציפית ביותר ראשונה. אין מילת מפתח elif או elseif.

למה אי אפשר לכתוב if (count) ב-C#?

תנאי ב-C# חייב להיות מטיפוס bool. בניגוד ל-C ול-JavaScript, int, מחרוזת או אובייקט אף פעם לא מומרים ל-true או ל-false, ולכן if (count) נכשל עם CS0029, Cannot implicitly convert type 'int' to 'bool'. כתבו את הבדיקה שאתם מתכוונים אליה: if (count > 0) או if (name != null).

מה ההבדל בין && ל-& בתנאי if?

&& מבצע הערכה מקוצרת (short-circuit): אם הצד השמאלי שקרי, הצד הימני לא מחושב בכלל, וזה מה שהופך את s != null && s.Length > 0 לבטוח. & על שני bool מחשב את שני הצדדים בכל פעם. אותו דבר חל על || ו-|. השתמשו ב-&& וב-|| בתנאים, אלא אם אתם צריכים את תופעת הלוואי של הצד הימני.

האם חובה לכתוב סוגריים מסולסלים בפקודת if ב-C#?

לא. בלי סוגריים מסולסלים ה-if שולט בפקודה אחת בדיוק. הזחה של שורה שנייה לא מוסיפה אותה לענף, וזה מקור קלאסי לבאגים, ולכן רוב מדריכי הסגנון ממליצים על סוגריים מסולסלים בכל ענף.

אפשר לכתוב if else בשורה אחת ב-C#?

כדי לבחור ערך, השתמשו באופרטור התנאי: string label = score >= 50 ? "pass" : "fail";. כדי להריץ פקודות, if (x) DoA(); else DoB(); חוקי בשורה אחת, אבל קשה יותר לקרוא ולהרחיב אותו מאשר בלוק עם סוגריים מסולסלים.

איור של שפות התכנות ב-Coddy

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

להתחיל