Egy program futás közben általában normál állapotban van. Ha a futás közben kezeletlen hibára fut (például nullával való osztás, olyan fájl megnyitása, amely éppen nem elérhető, stb.), hiba állapotba kerül a program és az operációs rendszer, illetve a futási környezet által nyújtott hibakezelő rutinok a program futását megszakítják és a program nem fog tovább futni, pontosabban a hiba helyétől a program visszatér a hívási listán keresztül a belépési függvényéig - Main() - és befejezi működését.
Erre azt mondjuk hogy kivétel történt (Exception) a program futásában. Ha nincsen kivételkezelés (Exception handling), akkor a program leáll.
A C#-ban, mint más nyelven gondot kell lehet fordítani arra, hogy a program futása közben előforduló, előre nem látható, külső körülményekből álló hibákat kezeljük. A komolyabb programoknál nem elegendő az, hogy az operációs rendszer ezt majd megoldja, hanem olyan értelmes megoldások kellenek, amelyeket a programozók kézben tartanak és a felhasználókat a hibák esetén normális módon lehet értesíteni.
Hibakezelés hagyományosan
Az alábbiakban egy példán keresztül megmutatom a hibakezelés hagyományos módját.Tegyük fel, hogy egy adatbevitel során egy változót be lehet vinni a billentyűzetről, majd ennek a változónak az értékével osztani akarunk. Hogyan lehet elkerülni, hogy a 0-val való osztás hibát okozzon?
string sszamlalo;
int szamlalo;
string snevezo;
int nevezo;
int eredmeny;
Console.Write("Kérem a számlálót:");
sszamlalo = Console.ReadLine();
szamlalo = int.Parse(sszamlalo);
Console.Write("Kérem a nevezőt:");
snevezo = Console.ReadLine();
nevezo = int.Parse(snevezo);
if (nevezo != 0 )
{
eredmeny = szamlalo / nevezo;
Console.WriteLine("AZ eredmény: {0}",eredmeny);
}
else
{
Console.WriteLine("Hiba! A nevező nem lehet 0");
}
A fenti program még az osztás művelet elvégzése előtt megvizsgálja, hogy a nevezo nulla vagy nem nulla. Ha a nevező nulla, akkor a program kiírja, hogy a nevező nem lehet nulla és folytatja a működését.
Ilyen és ehhez hasonló módon ki lehet küszöbölni, hogy egy program az előre látható hibákat hogyan kezelje. Nagyon sok esetben azonban nem lehet előre látni minden problémát, sőt kifejezetten a felhasználói interakciókban sok olyan helyzet fordul elő, amikor a felhasználó irracionálisan viselkedik.
Ha egy kis gyereket odaültetünk egy számítógéphez, hogy kezdj valamit a futó programmal, ő minden elképzelhető és elképzelhetetlen hibát produkálni fog. Tehát nagyon nehéz minden hibára felkészülni.
A fenti programban, ha egy nem numerikus szöveget viszünk be a programba, akkor az int.Parse() utasítás hibát okoz és a program leáll, vagyis ezt is kellene kezelni!
Ameddig a programozási nyelvekben nem voltak a hibakezelésre szabványosított eszközök, addig meglehetősen meglehetősen nehezen lehetett előre felkészülni minden lehetséges hibára, azonban ma már minden elterjedt programozási nyelv tartalmazza azokat a nyelvi elemeket, amelyeket kifejezetten a kivételkezelésre lehet használni.
Kivételkezelés - try{} catch{}
A kivételkezelő utasításoknak az a lényege, hogyha a program futása közben kivétel keletkezik, akkor a program futása ne fejeződjön be automatikusan, hanem értelmes üzenetet, vagy tevékenységet végezve a program fusson tovább és legyen továbbra is használható állapotban. Persze, hogy mit jelent az értelmes üzenet vagy tevékenység annak meghatározása továbbra is a programozó feladata. Erre használható a try{} catch{} utasítás blokk. A fenti kód kivételkezeléssel így írható le:
string sszamlalo;
int szamlalo = 0;
string snevezo;
int nevezo = 0;
int eredmeny;
bool ok = false;
while(! ok){
try{
Console.Write("Kérem a számlálót:");
sszamlalo = Console.ReadLine();
szamlalo = int.Parse(sszamlalo);
ok = true;
}catch{
Console.WriteLine("A számláló csak numerikus lehet!");
ok = false;
}
}
ok = false;
while(!ok){
try{
Console.Write("Kérem a nevezőt:");
snevezo = Console.ReadLine();
nevezo = int.Parse(snevezo);
ok = true;
}catch{
Console.WriteLine("A nevező csak numerikus lehet és nem lehet nulla!");
ok = false;
}
}
try
{
eredmeny = szamlalo / nevezo;
Console.WriteLine("A eredmény: {0}",eredmeny);
}
catch
{
Console.WriteLine("Hiba! A nevező nem lehet 0");
}
Ha összehasonlítjuk az eredeti kóddal, akkor azt látjuk, hogy hasonló hozzá, de mégis más. eleve ez a kód lekezel minden felhasználói hibát. Nem csak a 0-ával való osztás problémáját, hanem azt is, hogyha a felhasználó értelmetlen adatokat visz be a billentyűzetről.
A try ...catch... utasításpár még további lehetőségeket is tartalmaz.
A C#-ban vannak a hibakezelés céljára előre meghatározott hibakezelú objektumok, amelyek az ős hibakezelő leszármazottjai. Az objektumoknak van egy Message része, amelynek segítségével szabványos hibaüzeneteket lehet kiírni a felhasználó részére.