# טיפול בשגיאות (Exceptions) — בסיסי📖 שיעור

## מה זה?

לאורך היחידה נתקלנו כבר בכמה שגיאות ריצה: `int.Parse("abc")` שזורק `FormatException`, גישה לאינדקס לא קיים במערך שזורקת `IndexOutOfRangeException`, קריאה ל-`.Value` על Nullable ריק. בלי טיפול, כל אחת מהן **מפילה את כל התוכנית** מיד — גם אם השגיאה קרתה בפעולה קטנה ולא קריטית. `try`/`catch` פותר את זה: "נסה להריץ את הקוד הזה — ואם הוא נכשל, טפל בזה בעדינות במקום לקרוס".

## מילות מפתח שחשוב לזכור

• Exception — אובייקט שמייצג שגיאה שקרתה בזמן ריצה; "נזרק" (throw) כשמשהו משתבש

• `try` — הבלוק שבו מריצים קוד שעלול לזרוק חריגה

• `catch` — הבלוק שרץ **רק** אם נזרקה חריגה בתוך ה-`try`; תופס אותה ומטפל בה

• `finally` — בלוק שרץ **תמיד**, בין אם הייתה חריגה ובין אם לא — לניקוי משאבים

```csharp
try
{
    Console.Write("Enter a number: ");
    string input = Console.ReadLine();
    int number = int.Parse(input);   // may throw FormatException
    Console.WriteLine($"Double: {number * 2}");
}
catch (FormatException)
{
    Console.WriteLine("Invalid input — a number is required");
}
```

```csharp
// finally — always runs, even if an exception occurred
try
{
    Console.WriteLine("Starting operation...");
    int[] numbers = { 1, 2, 3 };
    Console.WriteLine(numbers[10]);   // throws IndexOutOfRangeException
}
catch (IndexOutOfRangeException)
{
    Console.WriteLine("Access to a non-existent index");
}
finally
{
    Console.WriteLine("Operation finished");   // runs no matter what
}
```

## הסבר עיקרי

למה `catch` "שקט" מסוכן — אם תופסים חריגה בלי לעשות כלום איתה (`catch { }` ריק), השגיאה נעלמת בלי עקבות — התוכנית ממשיכה כאילו הכל בסדר, אבל משהו באמת נכשל. לפחות `Console.WriteLine` שמדפיס מה קרה הוא המינימום, כדי שהבעיה לא "תיעלם" בשקט.

`finally` מבטיח ניקוי — קוד ב-`finally` רץ **תמיד**, גם אם ה-`try` הצליח וגם אם נזרקה חריגה ונתפסה ב-`catch`. זה שימושי לפעולות שחייבות לקרות בכל מקרה — למשל סגירת קובץ פתוח (נראה בשיעור IO מתקדם), גם אם הקריאה ממנו נכשלה באמצע.

יותר מ-`catch` אחד לסוגי שגיאה שונים — אפשר לכתוב כמה בלוקי `catch` ברצף, כל אחד לסוג חריגה אחר (`catch (FormatException)`, `catch (IndexOutOfRangeException)`), כדי לתת הודעה מדויקת יותר לכל תקלה במקום הודעה כללית אחת. C# בודקת אותם בסדר, ומריצה את הראשון שמתאים לסוג החריגה שנזרקה בפועל.

## יתרונות

`try`/`catch` מונע קריסה מוחלטת של התוכנית על שגיאת ריצה בודדת; אפשר לתת למשתמש הודעה ברורה במקום Stack Trace מפחיד; `finally` מבטיח שפעולות ניקוי קריטיות קורות בכל מקרה.

## חסרונות

תפיסת חריגות רחבה מדי (`catch (Exception)` לכל דבר) מסתירה בעיות אמיתיות שהיה עדיף לגלות ולתקן; שימוש ב-`try`/`catch` כתחליף לבדיקה מונעת (למשל `TryParse` במקום `try`/`catch` סביב `Parse`) לרוב פחות יעיל וברור.

## נקודות חשובות

• `try` מכיל קוד שעלול להיכשל; `catch` תופס ומטפל בכישלון; `finally` רץ תמיד

• `catch` ריק/שקט מסתיר בעיות במקום לפתור אותן — אנטי-פטרן מוכר

• אפשר כמה בלוקי `catch` לסוגי חריגה שונים, נבדקים ברצף

• `TryParse` עדיף על `try`/`catch` סביב `Parse` כשהמטרה רק לבדוק תקינות קלט

## טעויות נפוצות

• להשאיר בלוק `catch` ריק לגמרי — השגיאה "נעלמת" בלי עקבות ובלי הזדמנות לתקן

• לתפוס `Exception` הכללי ביותר במקום סוג ספציפי, ולפספס פרטים שהיו עוזרים לאבחן את הבעיה

• לשכוח ש-`finally` רץ **גם** כשיש `return` בתוך ה-`try` — הוא לא "מדולג" בטעות

## סיכום

`try`/`catch` מאפשר לתפוס שגיאות ריצה (Exceptions) בעדינות במקום לתת להן להפיל את כל התוכנית — קוד שעלול להיכשל נכתב ב-`try`, והטיפול בכישלון ב-`catch`. `finally` מבטיח שקוד ניקוי חיוני רץ תמיד, בין אם הייתה שגיאה ובין אם לא. חשוב לתפוס סוגי חריגה ספציפיים ולתת להן טיפול משמעותי — לא רק "לבלוע" אותן בשקט.

## דוקומנטציה רשמית

[Microsoft Learn — Exception handling](https://learn.microsoft.com/dotnet/csharp/fundamentals/exceptions/exception-handling)

---

## תרגילים

### תרגיל 1 — try/catch על קלט

**המשימה:** עטפו קריאה ל-`int.Parse` על קלט משתמש ב-`try`/`catch`, ותפסו `FormatException` עם הודעה ברורה.

**בדיקה:** קלט תקין מדפיס את התוצאה כרגיל; קלט לא תקין (`"abc"`) מדפיס הודעת שגיאה ידידותית במקום לקרוס.

### תרגיל 2 — finally

**המשימה:** כתבו `try`/`catch`/`finally` שמדפיס "מתחיל" לפני הפעולה, מבצע חלוקה שעלולה לזרוק `DivideByZeroException`, ומדפיס "הסתיים" תמיד ב-`finally`.

**בדיקה:** גם בחלוקה תקינה וגם בחלוקה ב-0, השורה "הסתיים" מודפסת בסוף בכל מקרה.

---

## פרויקט מסכם

**המשימה:** כתבו תוכנית "מחשבון בטוח" שמקבלת מהמשתמש שני מספרים ופעולה (`+`, `-`, `*`, `/`), ומטפלת בכל תקלה אפשרית בעדינות.

**דרישות:**
1. `try`/`catch` סביב כל הזרימה — קלט לא תקין (`FormatException`) וחלוקה ב-0 (`DivideByZeroException`) מטופלים בנפרד, כל אחד עם הודעה משלו
2. `finally` שמדפיס "התוכנית הסתיימה" בסוף, בכל מקרה
3. אם החישוב הצליח — הדפיסו את התוצאה בפורמט ברור

**בדיקה:** קלט תקין עם פעולה תקינה מדפיס תוצאה נכונה; קלט לא מספרי מדפיס הודעת שגיאה מתאימה; חלוקה ב-0 מדפיסה הודעה משלה — ובכל שלושת המקרים, "התוכנית הסתיימה" מודפס בסוף.

## מה בפרק הבא

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