cs

Obsługa wyjątków w języku C#.

W języku C# wyjątki (exceptions) to mechanizm obsługi błędów, który pozwala reagować na nieoczekiwane sytuacje w czasie wykonywania programu.

Opisz jakie zadanie pełnią następujące słówka kluczowe w języku c#:

try -

catch -

finally -

Które z tych bloków możemy pominąć? Które są wymagane?

Jeśli musimy wywołać fragment kodu po wystąpieniu wyjątku aby np. przywrócić hermetycznosć klasy ale nie chcemy przechwytywać wyjątku, z jakich bloków skorzystamy? Podaj przkład kodu.

Zgłaszanie wyjątków

Większość wyjątków w C# dziedziczy po klasie Exception. Wyjątki wystemowe dziedziczą po SystemException. Aby zgłosić wyjątek w trakcie działania programu używamy słówka throw, następnie tworzymy obiekt wyjątku który chcemy zwrócić.

Znajdź klasy odpowiadające za zgłaszanie następujących oraz podaj przykłady kodu kiedy dany wyjątek występuje:

Nieprawidłowy argument metody -

Przekazano null, ale wymagano wartości -

Wartość argumentu poza zakresem -

Operacja niewłaściwa dla bieżącego stanu obiektu -

Odwołanie do obiektu, który ma wartość null -

Przekroczenie zakresu tablicy -

Dzielenie przez zero -

Błędy we/wy, np. brak dostępu do pliku -

Plik nie został znaleziony -

Brak uprawnień do operacji -

Przepełnienie stosu -

Dzielenie przez zero -

Dzielenie przez zero -

Dzielenie przez zero -

Tworzenie wyjątków

Kiedy standardowe wyjątki (np. ArgumentException, InvalidOperationException) nie pasują do sytuacji, kiedy chcemy przekazać dodatkowe dane w wyjątku, gdy chcemy zachować jednolity sposób obsługi błędów w aplikacji c# umożliwia tworzenie własnych wyjątków.

Aby stworzyć własny wyjątek w C#, należy utworzyć klasę, która dziedziczy po Exception lub jednej z jej pochodnych (np. ApplicationException).

public class MyCustomException : Exception
{
    public MyCustomException() { }

    public MyCustomException(string message) : base(message) { }

    public MyCustomException(string message, Exception innerException) : base(message, innerException) { }
}

Wybrane właściwości klasy wyjątków (ang. properties)

Zainicjalizuj blok try w którym wyrzucisz wyjątek. Następnie w bloku catch spróbuj wypisać co zawierają poszczeólne właściwości wyrzuconego obiektu. Następnie opisz co przechowują poszczególne właściwości.

Message -

StackTrace -

InnerException -

try
{
    try
    {
        throw new ArgumentNullException("parametr", "Parametr nie może być null.");
    }
    catch (ArgumentNullException ex)
    {
        throw new InvalidOperationException("Błąd w operacji biznesowej.", ex);
    }
}
catch (Exception ex)
{
    Console.WriteLine("=== Ścieżka błędu ===");
    Exception currentEx = ex;
    while (currentEx != null)
    {
        Console.WriteLine($"Wyjątek: {currentEx.GetType()} - {currentEx.Message}");
        currentEx = currentEx.InnerException;
    }
}

Source -

HResult -

Wybrane metody wyjątków

Podobnie jak poprzednio utwórz kod który zawsze wyrzuca wyjątek a w bloku obsługującym go wywołaj poniższe metody. Następnie sporządź opis co robią podane metody.

ToString() -

GetType() -

GetBaseException() -

Equals(object obj) -

GetHashCode() -

Obsługa wyjątków

Obsługa wielu wyjątków

Jeśli dany fragment programu może zwrócić różne wyjątki możliwe jest wielokrotne użycie bloku catch aby przechwycić różne typy wyjątków:

try
{
    int[] numbers = new int[3];
    Console.WriteLine(numbers[5]); // IndexOutOfRangeException
}
catch (IndexOutOfRangeException ex)
{
    Console.WriteLine($"Błąd indeksu: {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"Inny błąd: {ex.Message}");
}

Jeśli chcemy obsłużyć wyjątków w ten sam sposób/w jednym bloku od C# 8.0 jest to możliwe w poniższy sposób:

catch (ArgumentException or FormatException ex)
{
    Console.WriteLine("Błąd argumentu lub formatu.");
}

Filtrowanie wyjątków

Wyjątki możemy również filtrować - np. obsługiwać dany wyjątek jeśli wiadomosć zawiera podany teskt. Używając słowa kluczowego when, możemy dodać dodatkowe warunki, które muszą być spełnione, aby dany wyjątek został obsłużony.

catch (Exception ex) when (ex.Message.Contains("specjalny"))
{
    Console.WriteLine("Złapano wyjątek zawierający 'specjalny'.");
}

Obsługa przepełnienia*

W C# checked i unchecked kontrolują przepełnienie arytmetyczne dla operacji na liczbach całkowitych (int, long, short, byte, itp.). Przepełnienie występuje, gdy wynik operacji przekracza zakres typu danych. Przykład dla int (-2 147 483 648 do 2 147 483 647). Domyślnie dla operacji arytmetycznych wykorzystywane jest unchecked.

checked – Włącza sprawdzanie przepełnienia

unchecked – Wyłącza sprawdzanie przepełnienia

checked
{
    int max = int.MaxValue;
    int result = max + 1; // Powoduje wyjątek OverflowException
}
unchecked
{
    int max = int.MaxValue;
    int result = max + 1; // Brak wyjątku! Wynik: -2147483648
}

Zadania

Zadanie 1

Napisz program, który prosi użytkownika o wprowadzenie dwóch liczb całkowitych. Następnie program wykonuje dzielenie jednej liczby przez drugą i wyświetla wynik. Jakie wyjątki mogą wystapić w czasie działania programu? Obsłuż wystepujące wyjątki wyświetlając stosowne komunikaty w konsoli oraz dajac użytkownikowi mozliwość poprawy błędów.

-Jeśli użytkownik poda 0 jako dzielnik, program wyświetli komunikat o błędzie.

-Jeśli użytkownik wprowadzi coś, co nie jest liczbą całkowitą, program wyświetli komunikat o błędzie.

Zadanie 2

Stwórz własny wyjątek NegativeNumberException, który będzie rzucany, gdy użytkownik poda liczbę ujemną. InvalidEmailException, który będzie wyrzucany gdy wpisany email jest prawidłowy. InvalidPhoneNumberException, który będzie rzucany gdy numer telefonu nie jest w formacie 000-000-000 lub innym prawidłowym. Program powinien demonstrować obsługę stworoznych wyjątków, przypadki brzegowe gdy dane wyjątki wystepują.

Zadanie 3

Dana jest metoda symująca działanie żądań http zwracająca wyjątki HttpRequestException:

public static HttpResponseMessage SimulateHttpRequest(string url)
   {
       if (url == "/moved")
       {
           // Zwraca kod 301 - Moved Permanently (przekierowanie)
           throw new HttpRequestException("301 - Moved Permanently");
       }
       else if (url == "/notfound")
       {
           // Zwraca kod 404 - Not Found (nie znaleziono zasobu)
           throw new  HttpRequestException("404 - Not Found");
       }
       else if (url == "/ok")
       {
           // Zwraca kod 200 - OK (żądanie udane)
           return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
       }
       else
       {
           // Zwraca kod 500 - Internal Server Error (błąd serwera)
           throw new HttpRequestException("500 - Internal Server Error");
       }
   }

Zasymuluj zapytania pod odpowiednie endpointy oraz obsłuż wyjątki (301, 404, 500) w zależności od kodu błędu: 301 wyświetl w konsoli - Błąd: Przekierowanie (301) - Zasób został przeniesiony. 404 wyświetl w konsoli - Błąd: Zasób nie znaleziony (404). 500 wyświetl w konsoli - Błąd: Błąd serwera (500). Proszę spróbować ponownie później.

Wykorzystaj słówko kluczowe when.