→ Slide 1

Obsługa wyjątków

→ Slide 2

Typy wartościowe mają wersję typu umożliwiającą przypisanie wartości null.

Deklaracja:

 typ? nazwa = null;

Przykład:

int? a = null;
int? b = 42;
double? x = null;
bool? czy_prawda = null;
 
//int k = null; // ta deklaracja nie jest dozwolona
→ Slide 3

Operator ?? ułatwia obsługę sytuacji, gdy zmienna posiada wartość null. W takiej sytuacji ?? zwraca wartość podaną po prawej stronie.

int? x = null;
int y = x ?? 42;
string linia = Console.ReadLine() ?? "";

Równoważnie

if (x == null) y = 42; 
→ Slide 4

Źródło: Learn Coding from Experts

  • Wyjątki - odpowiedź na nieoczekiwane zdarzenia w trakcie wykonywania programu, np. dzielenie przez zero, niepoprawne rzutowanie.
  • Wystąpienie wyjątku przerywa działanie programu
  • Rzucony wyjątek możemy „złapać” zabezpieczając wrażliwy fragment kodu instrukcją try catch
  • Informacje o wyjątkach rzucanych z metody opisane są w dokumentacji
    Przykład: Convert.ToInt32()
  • Rzucanie wyjątków, instrukcja throw
  • Predefiniowane wyjątki System.Exception
→ Slide 5

Składnia

try
{
   // blok kodu, w którym spodziewamy się wyjątku
}
catch(TypWyjątku ex)
{
   // obsługa wyjątku konkretnego typu
}
→ Slide 6
string napis = Console.ReadLine();
int wynik = 0;
 
try
{
    wynik = Convert.ToInt32(napis);
    Console.WriteLine($"Zamieniam '{napis}' na wartość typu int {wynik}.");
}
catch (FormatException) 
{
    Console.WriteLine($"'{napis}' nie jest liczbą całkowitą.");
}
→ Slide 7
string napis = Console.ReadLine();
int wynik = 0;
 
try
{
    wynik = Convert.ToInt32(napis);
    Console.WriteLine($"Zamieniam napis '{napis}' na wartość typu int {wynik}.");
}
catch (OverflowException) 
{
    Console.WriteLine($"{napis} jest poza zakresem typu int");
}
catch (FormatException) 
{
    Console.WriteLine($"Napis '{napis}' nie jest liczbą całkowitą.");
}
→ Slide 8

→ Slide 9
  • Wyjątki zorganizowane są w hierarchię
  • Każdy wyjątek jest typu System.Exception (najogólniejszy)

→ Slide 10
try
{
    int wynik = Convert.ToInt32("Ala ma kota");
}
catch(Exception e)
{
    Console.WriteLine($"Złapałem wyjątek {e}");
}
→ Slide 11

Sekcja finally jest uruchamiana na końcu sekcji try/catch, wykorzystywana jest do zwalniania zasobów zarezerwowanych w instrukcji try (np. zamknięcie pliku)

try
{
   // blok kodu, w którym spodziewamy się wyjątku
}
catch(TypWyjątku ex)
{
   // obsługa wyjątku konkretnego typu
}
finally
{
   // Kod uruchamiany ZAWSZE, niezależnie od tego, czy wystąpił wyjątek 
}
→ Slide 12
Typ Opis
ArithmeticException błędna operacja arytmetyczna (dzielenie przez 0, nadmiar)
DivideByZeroException dzielenie przez zero
OverflowException nadmiar, przekroczenie zakresu typu
ArrayTypeMismatchException niepoprawny typ elementu tablicy
IndexOutOfRangeException indeks poza zakresem tablicy
InvalidCastException niepoprawne rzutowania
NullReferenceException odwołanie do wartości null zamiast do obiektu
OutOfMemoryException brak pamięci (niepowodzenie operacji new)
ArgumentException niepoprawny argument metody
StackOverflowException przepełnienie stosu (np. nieskończona rekurencja)
IO.IOException błąd obsługi wejścia/wyjścia (pliki)
IO.FileNotFoundException próba dostępu do nieistniejącego pliku
→ Slide 13

W sytuacjach wyjątkowych rzucamy wyjątek odpowiedniego typu

throw new Exception("Komunikat wyjątku");
if(x == 0) throw new DivideByZeroException(); 
int y=1 / x;
→ Slide 14

Niektóre metody komunikują wystąpienie błedu zwracając odpowiednia wartość

int x;
string s = Console.ReadLine();
 
if (int.TryParse(s, out int wartość))
{
    x = wartość; 
}
else
{
    Console.WriteLine("Błąd formatowania");
}
→ Slide 15

Napisz metodę wyznaczającą pierwiastek kwadratowy $\sqrt{a}$ liczby rzeczywistej za pomocą algorytmu Herona. W przypadku niepoprawnego argumentu $a<0$ metoda rzuca wyjątek ArgumentException z odpowiednim komunikatem.

Napisz program, który wczyta z konsoli liczbę i wyznaczy jej pierwiastek kwadratowy. Obsłuż wszystkie sytuacje wyjątkowe (niepoprawny format liczby, zły argument metody pierwiastkującej).

Przybliżenie pierwiastka liczby $a$ wyznaczamy wzorem iteracyjnym

$$x_{i+1} =\frac{1}{2} \left( x_i + \frac{a}{x_i}\right)$$

Algorytm:

  1. ustaw wartości początkowe $x_0=1, i=0, \epsilon=0.0000001$
  2. oblicz $x_{i+1}$
  3. jeśli $|x_{i+1} - x_i | < \epsilon$ to zwróć pierwiastek równy $x_{i+1}$
  4. zwiększ $i=i+1$ i wróć do pkt. 2