Letzte Haltestelle: Exception
Programme stürzen ab, das ist nun mal so.Natürlich kann man sich gegen den Fehlerfall schützen. Dafür gibt es in C# "try"- und "catch"-Befehle. Wichtige Befehle die einem geübten Programmieren vertraut sein sollten. Aber trotzdem können sich immer wieder Fehler einschleichen, die man nicht erwartet. Und das an Stellen im Programm, die unkritisch sein sollten. Die Gründe hierfür sind vielfältig aber das Resultat immer gleich. Das Programm stützt ab.
Dies mag schon tragisch genug sein, viel schlimmer ist es, dass man oftmals nicht weiß, an welcher Stelle das Programm den einen Fehler verursacht hat. Dagegen kann man aber etwas tun. Fehler, auch als Ausnahme oder Exceptions bekannt, können abgefangen und abgefragt werden. In der Regel passiert das in der Methode, in der der Fehler auftritt. Hat diese Methode keine Fehlerbehandlung, wird die Exception an die Methode weitergereicht, welche die Methode mit dem Fehler aufgerufen hat. Gibt es auch dort keine Fehlerbehandlung wird wieder nach oben weitergereicht, bis die Exception schließlich dort ankommt, wo alles begann.
In C#-Programmen ist das die Main Methode. Hier läuft alles zusammen und hier sollte auch eine Fehlerbehandlung sein, die dann aktiv wird, wenn es zuvor keine andere Fehlerbehandlung gab. Das könnte etwas so aussehen:
[STAThread]
static void Main()
{
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
catch(Exception ex)
{
MessageBox.Show(ex.Message + "\n\n"+ ex.TargetSite.ReflectedType +"."+ ex.TargetSite.Name, "Oops!...Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
static void Main()
{
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
catch(Exception ex)
{
MessageBox.Show(ex.Message + "\n\n"+ ex.TargetSite.ReflectedType +"."+ ex.TargetSite.Name, "Oops!...Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Die Exception selbst
ist ein Objekt mit verschiedenen Membervariablen.
Lässt man sich die in einer Messagebox anzeigen,
ist es viel leichter dem Fehler auf die Spur zu
kommen und das Programm beendet sich nicht mehr
kommentarlos.
Man sollte nicht verschweigen, das sich so ein try/catch-Block rund um die main-Methode durchaus negativ auf die Performace der Anwendung auswirken kann. Während der Entwicklung und bei der Fehlersuche kann es aber sehr nützlich sein.
Aber es gibt auch elegantere Vorgehensweisen, als die im letzen Beispiel gezeigte, mit den Fehlern eines Programmes umzugehen. Dazu muss man sich aber erst ein Mal vor Augen halten, was ein Fehler eigendlich ist. Auch eine Exception ist ein Ereignis, welches innerhalb eines Programmes stattfindet. Und so ist es nicht ungewöhnlich, dass man sich auch an dieses Ereignis, eine ThreadException, mit einer delegate-Methode anhängen kann.
Eine so angepasste Main-Methode könnte zum Beispiel so aussehen:
Man sollte nicht verschweigen, das sich so ein try/catch-Block rund um die main-Methode durchaus negativ auf die Performace der Anwendung auswirken kann. Während der Entwicklung und bei der Fehlersuche kann es aber sehr nützlich sein.
Aber es gibt auch elegantere Vorgehensweisen, als die im letzen Beispiel gezeigte, mit den Fehlern eines Programmes umzugehen. Dazu muss man sich aber erst ein Mal vor Augen halten, was ein Fehler eigendlich ist. Auch eine Exception ist ein Ereignis, welches innerhalb eines Programmes stattfindet. Und so ist es nicht ungewöhnlich, dass man sich auch an dieses Ereignis, eine ThreadException, mit einer delegate-Methode anhängen kann.
Eine so angepasste Main-Methode könnte zum Beispiel so aussehen:
[STAThread]
static void Main()
{
Application.ThreadException += new ThreadExceptionEventHandler(meineThreadExceptionBehandlung);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void Main()
{
Application.ThreadException += new ThreadExceptionEventHandler(meineThreadExceptionBehandlung);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
Was jetzt noch fehlt,
ist die die entsprechende Methode, die bei einem
Fehlerfall ausgeführt wird. Dort sollte man
natürlich alle Maßnahmen treffen, um das Programm
wieder in einen stabilen Zustand zu bringen. Im
folgenden Beispiel hat der Benutzer nur die Wahl
den Fehler zu ignorieren oder die Anwendung zu
schließen.
static void
meineThreadExceptionBehandlung(object sender,
ThreadExceptionEventArgs e)
{
DialogResult dia = MessageBox.Show(e.Exception.ToString(), "Ein Fehler ist aufgetreten (ThreadException)", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
if(dia == DialogResult.Cancel)
{
Application.Exit();
}
}
{
DialogResult dia = MessageBox.Show(e.Exception.ToString(), "Ein Fehler ist aufgetreten (ThreadException)", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
if(dia == DialogResult.Cancel)
{
Application.Exit();
}
}
Obwohl das Ereignis
im letzten Beispiel ThreadException heißt, ist es
nicht geeignet die Fehlerbehandlung in
Multithreading Szenarien zu übernehmen. Eine
ThreadException fängt ausschließlich die Fehler des
Hauptthreads. Will man auch mögliche Exception der
anderen Threads abfangen, ist eine Erweiterung des
Programmes nötig. Das Ereignis UnhandledException
in der AppDomain der Anwendung ist hierfür
geeignet.
Die erweiterte Main-Methode:
Die erweiterte Main-Methode:
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(meineUnhandledExceptionBehandlung);
Application.ThreadException += new ThreadExceptionEventHandler(meineThreadExceptionBehandlung);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(meineUnhandledExceptionBehandlung);
Application.ThreadException += new ThreadExceptionEventHandler(meineThreadExceptionBehandlung);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
Und eine weitere
Methode zur Fehlerbehandlung:
static void
meineUnhandledExceptionBehandlung(object sender,
UnhandledExceptionEventArgs e)
{
MessageBox.Show(e.ExceptionObject.ToString(), "Ein Fehler ist aufgetreten (UnhandledException)", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
{
MessageBox.Show(e.ExceptionObject.ToString(), "Ein Fehler ist aufgetreten (UnhandledException)", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Im Unterscheid zu
einer ThreadException ist es hier nicht möglich den
Fehler zu ignorieren. Die Anwendung wird sich immer
beenden. So hat man nun letztmalig Gelegenheit
kritische Daten zu speichern und einen
einigermassen sanften Abbruch
herbeizuführen.