JiPP 3
4. Instrukcje. Obsługa
wyj
ą
tków.
Włodzimierz Kasprzak
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
2
Treść
1.
Rodzaje instrukcji.
2.
Instrukcje wyboru.
3.
Instrukcje pętli.
4.
Instrukcje skoku.
5.
Podstawowe wyjątki.
6.
Zgłaszanie wyjątku.
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
3
1. Rodzaje instrukcji
Instrukcja złożona
Blok
Instrukcje sterujące
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
4
Instrukcja złożona. Blok.
Nawiasy { }
oznaczają
instrukcję złożoną
lub
blok instrukcji
.
Blok zawiera
przynajmniej jedną
instrukcję
deklaracji.
{
// instrukcje
}
{
// instrukcje
}
{
int i;
...
{
int i;
...
}
}
{
int i;
...
{
int i;
...
}
}
{
int i;
...
}
...
{
int i;
...
}
{
int i;
...
}
...
{
int i;
...
}
W bloku
wewnętrznym
nie
można powtórzyć
definicji tej samej
nazwy co
zdefiniowana w
bloku
zewnętrznym.
Definicje podane
w blokach
rozłącznych
nie
mają ze sobą
związku.
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
5
Instrukcje sterujące
Instrukcje wyboru
if , switch
Instrukcje wyboru
if , switch
Instrukcje pętli
while, do, for, foreach
Instrukcje pętli
while, do, for, foreach
Instrukcje skoku
goto, break, continue
Instrukcje skoku
goto, break, continue
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
6
2. Instrukcje wyboru
Instrukcja
if
Rozwijanie instrukcji
if
Instrukcja
switch
Test: wykryj błędy
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
7
Instrukcja
if
Składnia:
Nie ma niejawnej konwersji z
int
do
bool
int x;
...
if (x) ...
// Musimy pisać if (x != 0) w C#
if (x = 0) ... // Musimy pisać if (x == 0) w C#
int x;
...
if (x) ...
// Musimy pisać
if (x != 0)
w C#
if (x = 0) ... // Musimy pisać
if (x == 0)
w C#
if (
wyrażenie-logiczne
)
pierwsza-instrukcja-zagnieżdżona
else
druga-instrukcja-zagnieżdżona
if (
wyrażenie-logiczne
)
pierwsza-instrukcja-zagnieżdżona
else
druga-instrukcja-zagnieżdżona
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
8
Rozwijanie instrukcji
if
enum Suit { Clubs, Hearts, Diamonds, Spades }
Suit trumps = Suit.Hearts;
if (trumps == Suit.Clubs)
color = "Black";
else if (trumps == Suit.Hearts)
color = "Red";
else if (trumps == Suit.Diamonds)
color = "Red";
else
color = "Black";
enum Suit { Clubs, Hearts, Diamonds, Spades }
Suit trumps = Suit.Hearts;
if (trumps == Suit.Clubs)
color = "Black";
else if (trumps == Suit.Hearts)
color = "Red";
else if (trumps == Suit.Diamonds)
color = "Red";
else
color = "Black";
Dla wzajemnie wykluczających się opcji.
else
wiązane jest z najbliższym poprzedzającym
if
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
9
Zagnieżdżanie instrukcji
if
Potencjalne niebezpieczeństwo niejednoznaczności –
ale
else
wiązane jest z najbliższym poprzedzającym
if .
Np. zamiar programisty wynika ze struktury:
Ale interpretacja kompilatora jest inna:
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
10
Instrukcja
switch
switch
- stosowana dla wyboru spośród wielu alternatyw
break
jest wymagane dla zakończenia pola pojedynczej
alternatywy – nie ma „cichego” przejścia pomiędzy
alternatywami (przy braku
break
wystąpi błąd kompilacji)
Typem wyrażenia dla
switch
może być:
int, char, enum,
string
switch (trumps) {
case Suit.Clubs :
case Suit.Spades :
color = "Black"; break;
case Suit.Hearts :
case Suit.Diamonds :
color = "Red"; break;
default:
color = "ERROR"; break;
}
switch (trumps) {
case Suit.Clubs :
case Suit.Spades :
color = "Black"; break;
case Suit.Hearts :
case Suit.Diamonds :
color = "Red"; break;
default:
color = "ERROR"; break;
}
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
11
Instrukcja
switch
Grupowanie alternatyw
case
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
12
Instrukcja
switch
Wykorzystanie instrukcji
goto
Wymusza przejście do innych
alternatyw, np. pozwala uniknąć
błędu z powodu braku
break
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
13
Przykład: wykryj błędy.
if number % 2 == 0 ...
if number % 2 == 0 ...
if (percent < 0) || (percent > 100) ...
if (percent < 0) || (percent > 100) ...
if (minute == 60);
minute = 0;
if (minute == 60);
minute = 0;
switch (trumps) {
case Suit.Clubs, Suit.Spades :
color = "Black";
case Suit.Hearts, Suit.Diamonds :
color = "Red";
defualt :
...
}
switch (trumps) {
case Suit.Clubs, Suit.Spades :
color = "Black";
case Suit.Hearts, Suit.Diamonds :
color = "Red";
defualt :
...
}
2
2
2
3
3
3
4
4
4
1
1
1
Błąd
Błąd
Poprawne
3 błędy
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
14
3. Instrukcje pętli
Instrukcja
while
Instrukcja
do
Instrukcja
for
Instrukcja
foreach
Test: wykryj błędy
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
15
Instrukcja
while
Warunek pętli jest
wyrażeniem logicznym
.
Wyrażenie logiczne sprawdzane jest na początku pętli.
Instrukcja zawarta w pętli wykonuje się wtedy, gdy
warunekl logiczny przyjmuje wartość
True
.
int i = 0;
// Inicjalizacja zmiennej - warunku p
ę
tli
while (i < 10) {
// Warunek p
ę
tli
Console.WriteLine(i);
// Instrukcja zawarta w p
ę
tli
i++;
// Instrukcja modyfikuj
ą
ca warunek p
ę
tli
}
int i = 0;
// Inicjalizacja zmiennej - warunku p
ę
tli
while (i < 10) {
// Warunek p
ę
tli
Console.WriteLine(i);
// Instrukcja zawarta w p
ę
tli
i++;
// Instrukcja modyfikuj
ą
ca warunek p
ę
tli
}
// Pętla wykona się dla i =
// 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
16
Instrukcja
do
Warunek
logiczny
dla iteracji instrukcji zawartej w pętli.
Warunek sprawdzany jest
na końcu pętli
- instrukcja
zawarta w pętli zawsze wykona się
przynajmniej raz,
a jest
powtarzana wtedy, gdy wartość warunku wynosi
True
.
Instrukcję należy zakończyć
średnikiem
int i = 0;
do {
Console.WriteLine(i);
i++;
} while (i < 10);
// Warunek zakończony średnikiem
int i = 0;
do {
Console.WriteLine(i);
i++;
} while (i < 10)
;
// Warunek zakończony średnikiem
// Pętla wykona się dla i =
// 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
17
Instrukcja
for
Instrukcje modyfikacji umieszczone są na początku pętli.
Zmienne definiowane w bloku
for
są widoczne jedynie w tym
zakresie – instrukcja
for
może być blokiem instrukcji.
W pętli
for
można iterować wiele zmiennych.
for (int i = 0; i < 10; i++) {
Console.WriteLine(i);
}
for
(int i = 0; i < 10; i++) {
Console.WriteLine(i);
}
// dla : 0 1 2 3 4 5 6 7 8 9
for (int i = 0; i < 10; i++)
Console.WriteLine(i);
Console.WriteLine(i);
// BŁ
Ą
D: i jest poza zakresem
for (int i = 0; i < 10; i++)
Console.WriteLine(i);
Console.WriteLine(
i
);
// BŁ
Ą
D: i jest poza zakresem
for (int i = 0, j = 0; ... ; i++, j++ )
for (int
i = 0, j = 0
; ... ;
i++, j++
)
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
18
Instrukcja
foreach
W System.Collections istnieje klasa
ArrayList –
umożliwia
tworzenie kolekcji elementów określonego typu.
Pętla
foreach
- wykonuje zawarte w niej instrukcje dla
każdego elementu klasy kolekcyjnej. Należy podać typ i
nazwę iterowanej zmiennej
using System.Collections;
...
ArrayList numbers = new ArrayList( );
for (int i = 0; i < 10; i++ ) {
numbers.Add(i);
}
foreach (int number in numbers) {
Console.WriteLine(number);
}
using System.Collections;
...
ArrayList numbers = new ArrayList( );
for (int i = 0; i < 10; i++ ) {
numbers.Add(i);
}
foreach (int number in numbers) {
Console.WriteLine(number);
}
// dla: 0 1 2 3 4 5 6 7 8 9
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
19
Test: wykryj błędy
for (int i = 0, i < 10, i++)
Console.WriteLine(i);
for (int i = 0, i < 10, i++)
Console.WriteLine(i);
int i = 0;
while (i < 10)
Console.WriteLine(i);
int i = 0;
while (i < 10)
Console.WriteLine(i);
for (int i = 0; i >= 10; i++)
Console.WriteLine(i);
for (int i = 0; i >= 10; i++)
Console.WriteLine(i);
do
...
string line = Console.ReadLine( );
guess = int.Parse(line);
while (guess != answer);
do
...
string line = Console.ReadLine( );
guess = int.Parse(line);
while (guess != answer);
2
2
2
3
3
3
4
4
4
1
1
1
Nieskończona
pętla !
Błąd
Warunek nie do
spełnienia !
Błąd
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
20
4. Instrukcje skoku
Instrukcja
goto
Instrukcje
break
i
continue
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
21
Instrukcja
goto
Przeniesienie wykonywania programu do etykietowanej
instrukcji znajdującej się w
tym samym zakresie
.
Można wykonać skok na zewnątrz instrukcji złożonej ale
nigdy do wewnątrz bloku.
Stosowanie instrukcji
goto
nie jest zalecane w
programowaniu strukturalnym ani obiektowym. Jedyne
jej zastosowanie – w połączeniu z instrukcją
switch
.
if (number % 2 == 0) goto Even;
Console.WriteLine("odd");
goto End;
Even:
Console.WriteLine("even");
End:;
if (number % 2 == 0) goto Even;
Console.WriteLine("odd");
goto End;
Even:
Console.WriteLine("even");
End:;
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
22
Instrukcje
break
i
continue
Instrukcja
break
przerywa wykonanie pętli.
Instrukcja
continue
przerywa wykonanie aktualnej
iteracji danej pętli i przechodzi do następnej iteracji.
Ale można to samo osiągnąć bez skoków:
int i = 0;
while (true) {
Console.WriteLine(i);
i++;
if (i < 10)
continue;
else
break;
}
int i = 0;
while (true) {
Console.WriteLine(i);
i++;
if (i < 10)
continue
;
else
break
;
}
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
23
5. Podstawowe wyjątki
Motywacja
Klasy wyjątków
Bloki
try
i
catch
Wielokrotne bloki
catch
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
24
Motywacja
Tradycyjna obsługa błędów jest nieczytelna poprzez wstawienie
dodatkowych instrukcji sprawdzających poprawność danych jest
nieczytelna (
mieszają się fragmenty kodu
dla normalnej pracy z
fragmentami przeznaczonymi do sprawdzania i ewentualnej obsługi
błędów). Szczególne trudności sprawia
powrót do miejsc
obsługi błędów
oddalonych o wiele poziomów wywołań metod.
int errorCode = 0;
FileInfo source = new FileInfo("code.cs");
if (errorCode == -1) goto Failed;
int length = (int)source.Length;
if (errorCode == -2) goto Failed;
char[] contents = new char[length];
if (errorCode == -3) goto Failed;
... // tu wykona się sytuacja poprawna
Failed: ...
int errorCode = 0;
FileInfo source = new FileInfo("code.cs");
if (errorCode == -1) goto Failed;
int length = (int)source.Length;
if (errorCode == -2) goto Failed;
char[] contents = new char[length];
if (errorCode == -3) goto Failed;
... // tu wykona się sytuacja poprawna
Failed: ...
Obsługa błędu
Obsługa błędu
Normalny kod programu
Normalny kod programu
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
25
Klasy wyjątków
Exception
Exception
SystemException
SystemException
OutOfMemoryException
OutOfMemoryException
IOException
IOException
NullReferenceException
NullReferenceException
ApplicationException
ApplicationException
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
26
Bloki
try
i
catch
Obsługa wyjątków ma charakter obiektowy.
Zwykły kod programu umieszczany jest wewnątrz bloku
try
Obsługa błędów odbywa się w oddzielnym bloku
catch
try {
Console.WriteLine
(„Wprowad
ź
liczb
ę
"
);
int i = int.Parse(Console.ReadLine());
}
catch (OverflowException wyjatek)
{
Console.WriteLine(wyjatek);
}
try {
Console.WriteLine
(„Wprowad
ź
liczb
ę
"
);
int i = int.Parse(Console.ReadLine());
}
catch (OverflowException wyjatek)
{
Console.WriteLine(wyjatek);
}
Obsługa wyjątków
Obsługa wyjątków
Normalny program
Normalny program
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
27
Wielokrotne bloki
catch
Blok
catch
przejmuje obsługę wyjątków pewnej klasy.
try
{
Console.WriteLine(„Wprowadź pierwszą liczbę");
int i = int.Parse(Console.ReadLine());
Console.WriteLine(„Wprowadź drugą liczbę");
int j = int.Parse(Console.ReadLine());
int k = i / j;
}
catch (OverflowException wyjatek) {…}
catch (DivideByZeroException wyjatek) {…}
try
{
Console.WriteLine(„Wprowadź pierwszą liczbę");
int i = int.Parse(Console.ReadLine());
Console.WriteLine(„Wprowadź drugą liczbę");
int j = int.Parse(Console.ReadLine());
int k = i / j;
}
catch (OverflowException wyjatek) {…}
catch (DivideByZeroException wyjatek) {…}
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
28
Wielokrotne bloki catch
Blok
try
może posiadać
jeden
ogólny blok catch
.
Blok
catch
nie może przechwycić wyjątku będącego typu
klasy pochodnej od klasy wyjątku przechwyconego
przez
wcześniejszy blok catch.
catch {…}
...
// lub
...
catch (System.Exception) {…}
catch {…}
...
// lub
...
catch (System.Exception) {…}
catch (Exception wyjatek) {…}
catch (OutOfMemoryException wyjatek) {…}
// Bł
ą
d kompilacji
catch (Exception wyjatek) {…}
catch (OutOfMemoryException wyjatek) {…}
// Bł
ą
d kompilacji
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
29
6. Zgłaszanie wyjątków
Instrukcja
throw
Fraza
finally
Testowanie nadmiaru arytmetycznego
Zalecenia dla obsługi wyjątków
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
30
Instrukcja
throw
Zgłoszenie wyjątku odpowiedniego typu klasy pochodnej
od
System.Exception
.
Powinniśmy przekazać sensowną wiadomość poprzez
obiekt wyjątku.
throw
wyra
ż
enie
;
throw
wyra
ż
enie
;
if (minute < 1 || minute >= 60) {
throw new InvalidTimeException(minute +
" to nie jest poprawna liczba minut");
// Nigdy nie osi
ą
gniemy tego miejsca !!
}
if (minute < 1 || minute >= 60) {
throw new InvalidTimeException(minute +
" to nie jest poprawna liczba minut");
// Nigdy nie osi
ą
gniemy tego miejsca !!
}
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
31
Instrukcja
throw
W obsłudze wyjątku można
ponowić wyjątek
W obsłudze wyjątku można też zgłosić
nowy wyjątek
W bloku catch można też zgłosić
pusty wyjątek
– jest to
równoważne
ponowieniu obsługiwanego wyjątku
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
32
Fraza
finally
Wszystkie instrukcje umieszczone w bloku
finally
są zawsze
wykonywane – niezależnie od tego czy wystąpił wyjątek.
W bloku
finally
można zgłosić wyjątek. Jego obsługą zajmie się blok
catch
przy
zewnętrznym bloku try
. Aktualnie propagowany wyjątek
zostanie zgubiony.
Monitor.Enter(x); // Zainicjowanie zarządzanego zasobu
try {
...
}
finally {
Monitor.Exit(x); // Zwolnienie zarządzanego zasobu
}
Monitor.Enter(x); // Zainicjowanie zarządzanego zasobu
try {
...
}
finally {
Monitor.Exit(x); // Zwolnienie zarządzanego zasobu
}
Bloki catch są opcjonalne
Bloki catch są opcjonalne
try {
throw new PrzykladowyWyjatek(”Zostanie zgubiony”);
}
finally { throw new PrzykladowyWyjatek(”Zostanie przekazany”);
}
try {
throw new PrzykladowyWyjatek(”Zostanie zgubiony”);
}
finally { throw new PrzykladowyWyjatek(”Zostanie przekazany”);
}
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
33
Sprawdzenie arytmetycznego nadmiaru
Domyślnie wystąpienie nadmiaru w operacji arytmetycznej
nie
jest sprawdzane
Instrukcja
checked
aktywuje sprawdzanie nadmiaru.
Instrukcja
unchecked
deaktywuje sprawdzanie nadmiaru.
checked {
int number = int.MaxValue;
Console.WriteLine(++number);
}
checked {
int number = int.MaxValue;
Console.WriteLine(++number);
}
unchecked {
int number = int.MaxValue;
Console.WriteLine(++number);
}
unchecked {
int number = int.MaxValue;
Console.WriteLine(++number);
}
-2147483648
OverflowException
OverflowException
Zgłoszenie wyjątku.
Instrukcja z WriteLine nie
wykona się.
MaxValue + 1 jest ujemne?
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
34
Zalecenia dla obsługi wyjątków
Zgłaszanie
Unikaj
wyjątków
dla
sytuacji
normalnych
lub
spodziewanych problemów
Nigdy nie twórz i nie zgłaszaj obiektów klasy Exception
Przekaż napis z informacją do obiektu Exception
Zgłaszaj obiekty najbardziej specjalizowanej klasy wyjątków
Obsługa
Kolejność bloków catch - od specyficznego do ogólnego
Nie zezwalaj na wyjście wyjątków poza Main
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
35
Przykład 4.1: Konwersja liczby na datę
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
36
Przykład 4.1 (c.d.)
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
37
Przykład 4.2: Uzupełnienie programu 4.1 o wyjątki
W.Kasprzak: JiPP3
4. Instrukcje. Wyjątki.
38
Przykład 4.2 (c.d.)