Məzmuna keç
Educora
Orta17 dəq8 / 16

İstisnalar: xətaları tutmaq və atmaq

Proqram işləyərkən yaranan xətaları `try`, `catch` və `finally` ilə idarə et, `throw` ilə öz istisnalarını at və onları nə vaxt işlətməməli olduğunu öyrən.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • Kompilyasiya xətasını icra zamanı yaranan istisnadan fərqləndirmək
  • try, bir neçə catch bloku və finally ilə istisnaları tutmaq
  • throw ilə istisna atmaq və öz istisna sinfini yaratmaq
  • Gözlənilən səhvlər üçün TryParse kimi yolları seçmək

Kompilyator çox səhvi proqram işə düşməzdən əvvəl tapır, amma hamısını yox. İstifadəçi yaş əvəzinə «abc» yazır, fayl silinib, internet kəsilib, kimsə sıfıra bölür — bu problemlər yalnız proqram işləyərkən üzə çıxır. C#-da belə hallarda istisna (exception) yaranır. Onu tutmasan, proqram «Unhandled exception» mesajı ilə dayanır; tutsan, istifadəçiyə aydın izahat verib işi davam etdirə bilərsən.

try və catch

Xəta verə biləcək kod try blokuna yazılır. İstisna yaranan kimi try-ın qalan sətirləri buraxılır və idarə uyğun catch blokuna keçir. Hər catch müəyyən istisna tipini tutur, ona görə müxtəlif xətalara müxtəlif cür reaksiya vermək olar.

C#
string[] inputs = ["42", "abc", "99999999999"];

foreach (string input in inputs)
{
    try
    {
        int number = int.Parse(input);
        Console.WriteLine($"OK: {number}");
    }
    catch (FormatException)
    {
        Console.WriteLine($"'{input}' is not a number");
    }
    catch (OverflowException)
    {
        Console.WriteLine($"'{input}' is too big for int");
    }
}
Gözlənilən nəticə
OK: 42
'abc' is not a number
'99999999999' is too big for int

İstisna həm də obyektdir: catch (IndexOutOfRangeException ex) yazanda ex dəyişənində onun məlumatları olur, məsələn, ex.Message — izahat mətni. Bütün istisnalar Exception sinfindən törəyir, ona görə catch (Exception ex) istənilən xətanı tutur — onu həmişə sonuncu yaz. finally bloku isə xəta olsa da, olmasa da həmişə icra olunur: faylı bağlamaq və ya resursu azad etmək üçün uyğundur.

C#
int[] scores = [90, 75, 88];

try
{
    Console.WriteLine(scores[5]);
}
catch (IndexOutOfRangeException ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}
finally
{
    Console.WriteLine("This line always runs.");
}

try
{
    int zero = 0;
    Console.WriteLine(10 / zero);
}
catch (Exception ex)
{
    Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
Gözlənilən nəticə
Error: Index was outside the bounds of the array.
This line always runs.
DivideByZeroException: Attempted to divide by zero.
İstisnaNə vaxt yaranır
FormatExceptionint.Parse("abc") — mətn ədəd deyil
DivideByZeroExceptiontam ədəd sıfıra bölünür
IndexOutOfRangeExceptionmassivdə olmayan indeks
KeyNotFoundExceptionlüğətdə olmayan açar
NullReferenceExceptionnull olan dəyişənin üzvünə müraciət
FileNotFoundExceptionaçılmaq istənilən fayl yoxdur
Ən çox rast gəlinən istisnalar

throw: istisnanı özün atmaq

Metod işini düzgün görə bilmirsə, səssizcə yanlış nəticə qaytarmaq əvəzinə throw ilə istisna atmalıdır. Hazır tiplər çoxdur: ArgumentException — yanlış arqument, InvalidOperationException — obyektin indiki vəziyyətində icazəsiz əməliyyat. Lazım olsa, Exception-dan törəyən öz istisna sinfini yaratmaq olar — bu, keçən dərsdəki varisliyin real tətbiqidir.

C#
var wallet = new Wallet(100);
try
{
    wallet.Pay(30);
    wallet.Pay(250);
    wallet.Pay(10);
}
catch (NotEnoughMoneyException ex)
{
    Console.WriteLine($"Payment failed: {ex.Message}");
}
Console.WriteLine($"Left: {wallet.Balance} AZN");

class NotEnoughMoneyException(string message) : Exception(message);
class Wallet(decimal balance)
{
    public decimal Balance { get; private set; } = balance;
    public void Pay(decimal amount)
    {
        if (amount > Balance)
            throw new NotEnoughMoneyException($"need {amount} AZN, have {Balance} AZN");
        Balance -= amount;
        Console.WriteLine($"Paid {amount} AZN");
    }
}
Gözlənilən nəticə
Paid 30 AZN
Payment failed: need 250 AZN, have 70 AZN
Left: 70 AZN
wallet.Pay(10) heç icra olunmadı: istisnadan sonra try-ın qalanı buraxılır.

İstisnaları nə vaxt işlətməməli

İstisnalar gözlənilməz hallar üçündür. İstifadəçinin səhv yazması isə tamamilə gözləniləndir, ona görə mətni yoxlamaq üçün try/catch əvəzinə int.TryParse daha yaxşıdır: kod qısadır, daha sürətli işləyir və niyyəti aydın göstərir. Eyni qayda lüğətlərə də aiddir: TryGetValue açarın olmamasını xətasız yoxlayır.

C#
string[] answers = ["15", "fifteen", "-3"];

foreach (string answer in answers)
{
    if (!int.TryParse(answer, out int age))
        Console.WriteLine($"'{answer}': please type digits");
    else if (age is < 0 or > 120)
        Console.WriteLine($"'{answer}': age must be 0-120");
    else
        Console.WriteLine($"Age accepted: {age}");
}
Gözlənilən nəticə
Age accepted: 15
'fifteen': please type digits
'-3': age must be 0-120

Əsas fikirlər

  • İstisna proqram işləyərkən yaranan xətadır; tutulmasa, proqram dayanır.
  • try blokunda istisna yarananda qalan sətirlər buraxılır və uyğun catch işləyir.
  • Xüsusi catch blokları əvvəl, catch (Exception) sonda yazılır; finally həmişə icra olunur.
  • throw new ...Exception("...") səhv vəziyyəti bildirir; öz istisnalarını Exception-dan törət.
  • Gözlənilən səhvlər üçün TryParse və TryGetValue istisnalardan yaxşıdır.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
int.Parse("abc") hansı istisnanı yaradır?