| Exceptions i C# er i store træk som i Java. Alle exceptions er
instanser af en klasse der nedarver fra System.Exception.
|
|
1. try-catch-finally
|
catch
sukker
| try- og finally-blokke
fungerer på nøjagtig samme måde som i Java. Mht. catch-blokke
er der lidt syntaktisk sukker som vi vil se på i det følgende.
|
| Man kan som i Java have flere catch-blokke,
og der vælges på samme måde den catch-blok
der først passer. Hvis man i catch-blokken
ikke er interesseret i den konkrete exception, kan man udelade den formelle
parameters navn. F.eks.:
|
|
try {
int tæller = 5;
int nævner = 0;
int x = tæller / nævner;
}
catch ( DivideByZeroException ) {
Console.WriteLine( "Division med 0" );
}
|
|
|
|
| Her anvender vi ikke den exception, der bliver kastet, til andet end
at styre hvilken catch-blok
der bliver udført.
|
| Hvis man vil gribe enhver exception anfører man naturligvis blot
Exception, men
er man (som ovenfor) ikke interesseret i Exception-objektet,
kan man forkorte det til:
|
|
try {
int tæller = 5;
int nævner = 0;
int x = tæller / nævner;
}
catch {
Console.WriteLine( "Noget gik galt" );
}
|
|
|
|
|
2. Metode-kald
|
Ingen throws
| Ligesom i Java, vil en exception der ikke bliver håndteret i en
metode, blive kastet tilbage til, hvor metoden er blevet kaldt fra. I
C# er alle exceptions run-time exceptions, og man skriver derfor aldrig
throws...
efter metodens signatur, som man ellers kender det fra Java.
|
| Hvis man ikke håndterer en exception i sit program, og den dermed
bliver kastet videre fra Main,
får man en dialogbox:
|
|
|
| samt en fejlmeddelelse:
|
|
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Test.Main() in C:\Projects\C#\Test\Test.cs:line 5
|
|
|
|
| Hvis man griber en exception, og dernæst ønsker at kaste
den, skriver man blot throw.
F.eks.:
|
|
try {
int tæller = 5;
int nævner = 0;
int x = tæller / nævner;
}
catch ( DivideByZeroException e ) {
Console.WriteLine( e );
throw;
}
|
|
| Man bemærker at det er underforstået, at den exception der
kastes, er den catch-blokken
greb.
|
|
3. Wrappe exceptions
|
Ekstra information
| Når f.eks. en catch-blok
vælger at kaste en exception tilbage, til hvor metoden er blevet
kaldt fra, har man mulighed for at wrappe den i en ny exception, der kan
tilføjes ekstra information. F.eks.:
|
|
using System;
public class Test {
private static void M() {
try {
int tæller = 5;
int nævner = 0;
int x = tæller / nævner;
}
catch ( DivideByZeroException e ) {
throw new DivideByZeroException( "'nævner' er 0", e );
}
}
public static void Main() {
try {
M();
}
catch ( DivideByZeroException e ) {
Console.WriteLine( e );
}
}
}
|
|
|
System.DivideByZeroException: 'nævner' er 0 ---> System.DivideByZeroException:
Attempted to divide by zero.
at Test.M() in C:\Projects\C#\Test\Test.cs:line 10
at Test.M() in C:\Projects\C#\Test\Test.cs:line 13
at Test.Main() in C:\Projects\C#\Test\Test.cs:line 19
|
|
| Man ser af udskriften, at de to exceptions bliver listet efter hinanden.
Den vi selv har lavet:
|
|
System.DivideByZeroException: 'nævner' er 0
|
|
| Og den vi oprindelig greb:
|
|
System.DivideByZeroException: Attempted to divide by zero.
|
|
| Selv om vi har valgt det i dette eksempel, behøver de to exceptions
ikke nødvendigvis være af samme klasse
|
|
4. Egne exceptions
|
| Såfremt man laver sine egne exceptions skal de nedarve fra System.ApplicationException.
F.eks.:
|
|
using System;
class DivisionsException: ApplicationException {
int tæller;
public DivisionsException( int tæller ) {
this.tæller = tæller;
}
public DivisionsException( string message, int tæller ): base( message ) {
this.tæller = tæller;
}
public DivisionsException(
string message, Exception e, int tæller ): base( message, e )
{
this.tæller = tæller;
}
public int Tæller {
get {
return tæller;
}
}
}
public class Test {
private static void M() {
int tæller = 5;
int nævner = 0;
try {
int x = tæller / nævner;
}
catch ( DivideByZeroException e ) {
throw new DivisionsException( "'nævner' er 0", e, tæller );
}
}
public static void Main() {
try {
M();
}
catch ( DivisionsException e ) {
Console.WriteLine( "Division fejlede: {0}/0", e.Tæller );
}
}
}
|
|
|
|
| Man bør i den forbindelse lave de to konstruktorer - den der
tager en besked, og den anden der tillige tager en exception. Med dem
kan man instantiere ens egne exceptions på samme måde som
systemets (f.eks. når vi wrapper exceptions).
|
|
5. System.Exception
|
| Exception-klassen
har følgende tre properties som kan være nyttige (de er alle
kun get-properties):
|
|
Message
InnerException
StackTrace
|
|
| Message giver
den tekstuelle beskrivelse der er tilknyttet. F.eks.: "'nævner'
er 0", som vi har brugt ovenfor.
|
| InnerException
giver os den exception der evt. kan være wrapped i denne.
|
| StackTrace giver
os en tekstreng (med indsatte linieskift), der beskriver stien til det
sted hvor den er blevet kastet. F.eks.:
|
|
at Test.M() in C:\Projects\C#\Test\Test.cs:line 13
at Test.Main() in C:\Projects\C#\Test\Test.cs:line 19
|
|
| Man bemærker at Exception's
ToString bruger
de oplysninger vi kan få fra disse tre properties.
|
|
|
|
|