Enums
מה זה?
איך הייתם מייצגים סטטוס הזמנה — “ממתין”, “נשלח”, “בוטל”? אפשרות אחת: מספר (status = 1) — אבל מה זה 1? צריך לזכור מיפוי בראש. אפשרות שנייה: מחרוזת (status = "Pending") — אבל אפשר בטעות לכתוב "pending" (אות קטנה) או "Pendign" (שגיאת כתיב), וה-Compiler לא יתפוס את זה. enum פותר את שתי הבעיות: קבוצת שמות קבועה וסגורה, עם בדיקת טיפוסים מלאה בזמן קומפילציה.
מילות מפתח שחשוב לזכור
• enum — טיפוס שמגדיר קבוצה סגורה וקבועה של ערכים אפשריים, כל אחד עם שם ברור
• Underlying Value — כל ערך ב-enum מיוצג פנימית כמספר שלם (int כברירת מחדל), מתחיל מ-0
• Magic Number — מספר “חסר הקשר” בקוד (כמו status == 1) שקשה להבין בלי לחפש הגדרה
enum OrderStatus
{
Pending, // = 0 (default)
Shipped, // = 1
Delivered, // = 2
Cancelled // = 3
}
OrderStatus status = OrderStatus.Pending;
if (status == OrderStatus.Shipped)
{
Console.WriteLine("Order shipped");
}// switch on enum — readable and organized, and C# warns if you forget a case
string DescribeStatus(OrderStatus status) => status switch
{
OrderStatus.Pending => "Awaiting processing",
OrderStatus.Shipped => "On its way to you",
OrderStatus.Delivered => "Delivered successfully",
OrderStatus.Cancelled => "Cancelled",
_ => "Unknown status"
};הסבר עיקרי
enum מול Magic Number — if (status == 1) דורש שמישהו יזכור (או יחפש בתיעוד) ש-1 פירושו “נשלח”. if (status == OrderStatus.Shipped) קריא ומתעד את עצמו — אין צורך לזכור מיפוי מספרים. זו בדיוק אותה סיבה ש-const/שמות ברורים עדיפים על ערכים גולמיים — כאן זה מורחב לקבוצת ערכים שלמה.
למה enum עדיף על מחרוזת חופשית — עם string status = "Pending", שום דבר לא מונע status = "pendingg" (שגיאת הקלדה) — הקוד יתקמפל, והבאג יתגלה רק בזמן ריצה, אם בכלל. עם enum, OrderStatus.Pendingg פשוט לא מתקמפל — הקומפיילר בודק שהערך קיים בקבוצה הסגורה.
הערך המספרי מאחורי הקלעים — לכל איבר ב-enum יש ערך int מוצמד, שמתחיל מ-0 וגדל אוטומטית (אלא אם קובעים אחרת במפורש). זה שימושי לדעת, אבל ברוב הקוד עובדים עם השם (OrderStatus.Shipped), לא עם המספר — המספר הוא פרט מימוש פנימי.
יתרונות
מונע שגיאות הקלדה שקיימות במחרוזות חופשיות — הקומפיילר בודק את הערך; קוד קריא בהרבה מהשוואה למספרי-קסם; switch על enum מזהיר אם שכחתם לטפל במקרה קיים, מה שתופס באגים מוקדם.
חסרונות
הוספת ערך חדש ל-enum קיים דורשת לעדכן את כל מקומות ה-switch שמטפלים בו (אבל זו בדיוק ההגנה — עדיף לגלות את זה בקומפילציה מאשר בפרודקשן); enum לא מתאים לערכים שיכולים להשתנות דינמית בזמן ריצה (למשל רשימת קטגוריות שמנוהלת ב-DB).
נקודות חשובות
• enum = קבוצת ערכים סגורה וקבועה, נבדקת בזמן קומפילציה
• לכל ערך יש int מוצמד שמתחיל מ-0 כברירת מחדל
• enum עדיף על Magic Numbers ומחרוזות חופשיות לייצוג קבוצת אפשרויות קבועה
• switch על enum הוא שימוש נפוץ במיוחד — קריא ובטוח
טעויות נפוצות
• להשתמש במחרוזת חופשית (“Pending”) לייצוג סטטוס במקום enum — פתוח לשגיאות הקלדה
• לשכוח לטפל בכל הערכים האפשריים ב-switch על enum (למרות שה-Compiler בדרך כלל יתריע)
• להסתמך על הערך המספרי של enum ((int)status == 1) במקום על השם — פחות קריא ושביר יותר לשינויים
סיכום
enum מייצג קבוצת אפשרויות קבועה וסגורה עם שמות ברורים, ופותר את בעיית ה-Magic Numbers והמחרוזות החופשיות הפגיעות לשגיאות הקלדה. כל ערך מוצמד למספר int פנימי, אך בקוד עובדים עם השם — קריא, בטוח, ונבדק בזמן קומפילציה בדיוק כמו כל טיפוס אחר ב-C#.
דוקומנטציה רשמית
Microsoft Learn — Enumeration types
תרגילים
תרגיל 1 — enum ראשון
המשימה: הגדירו enum DayOfWeek עם שבעת ימות השבוע, וכתבו קוד שמדפיס האם היום הנוכחי (בחרו ערך קבוע לדוגמה) הוא יום עבודה או סוף שבוע.
בדיקה: DayOfWeek.Friday או DayOfWeek.Saturday מדפיסים “סוף שבוע”; כל יום אחר מדפיס “יום עבודה”.
תרגיל 2 — switch על enum
המשימה: הגדירו enum TrafficLight { Red, Yellow, Green }, וכתבו switch expression שמחזיר הוראה מתאימה לכל צבע (“עצור”, “היכון”, “סע”).
בדיקה: TrafficLight.Red מחזיר "עצור"; TrafficLight.Green מחזיר "סע".
פרויקט מסכם
המשימה: כתבו תוכנית ניהול הזמנות פשוטה עם enum OrderStatus { Pending, Shipped, Delivered, Cancelled }.
דרישות:
- פונקציה
AdvanceStatus(OrderStatus current)שמחזירה את הסטטוס הבא בתהליך (Pending→Shipped→Delivered), ומחזירהCancelledללא שינוי אם ההזמנה כבר בוטלה - פונקציה
DescribeStatus(כמו בדוגמה) שמתרגמת כל סטטוס למשפט בעברית - ב-
Main, הדגימו התקדמות מלאה של הזמנה אחת מ-PendingעדDelivered, עם הדפסת התיאור אחרי כל שלב
בדיקה: הפעלת AdvanceStatus שלוש פעמים ברצף על הזמנה חדשה מגיעה בדיוק ל-Delivered; קריאה נוספת על הזמנה Cancelled לא משנה את הסטטוס.
מה בפרק הבא
בפרק הבא — Value מול Reference, ו-out: מה קורה בפועל כשמעבירים משתנה לפונקציה — האם היא מקבלת עותק, או גישה למשתנה המקורי?