Übung: Abfangen bestimmter Ausnahmetypen
Weiter oben in diesem Modul haben Sie gelernt, dass die von Ihrer C#-Anwendung erfassten Ausnahmeobjekte Instanzen einer Ausnahmeklasse sind. Im Allgemeinen fängt Ihr Code (mit catch) eines der folgenden Objekte ab:
- Ein Ausnahmeobjekt, das eine Instanz der
System.ExceptionBasisklasse ist. - Ein Ausnahmeobjekt, das eine Instanz eines Ausnahmetyps ist, der von der Basisklasse erbt. Beispiel: eine Instanz der
InvalidCastExceptionKlasse.
Untersuchen von Ausnahmeeigenschaften
System.Exception ist die Basisklasse, von der alle abgeleiteten Ausnahmetypen erben. Jeder Ausnahmetyp erbt von der Basisklasse über eine bestimmte Klassenhierarchie. Die Klassenhierarchie für das InvalidCastException Beispiel lautet wie folgt:
Object
Exception
SystemException
InvalidCastException
Die meisten Ausnahmeklassen, die von Exception erben, fügen keine zusätzlichen Funktionen hinzu; sie erben einfach von Exception. Daher können Sie die Eigenschaften der Exception Klasse untersuchen, um die meisten Ausnahmen zu verstehen und wie Sie eine Ausnahme in Ihrem Code verwenden können.
Dies sind die Eigenschaften der Exception Klasse:
-
Daten: Die
DataEigenschaft enthält beliebige Daten in Schlüsselwertpaaren. -
HelpLink: Die
HelpLinkEigenschaft kann verwendet werden, um eine URL (oder URN) für eine Hilfedatei zu speichern, die umfangreiche Informationen zur Ursache einer Ausnahme bereitstellt. -
HResult: Die
HResultEigenschaft kann verwendet werden, um auf einen codierten numerischen Wert zuzugreifen, der einer bestimmten Ausnahme zugewiesen ist. -
InnerException: Die
InnerExceptionEigenschaft kann verwendet werden, um eine Reihe von Ausnahmen während der Ausnahmebehandlung zu erstellen und beizubehalten. -
Meldung: Die
MessageEigenschaft enthält Details zur Ursache einer Ausnahme. -
Quelle: Die
SourceEigenschaft kann verwendet werden, um auf den Namen der Anwendung oder das Objekt zuzugreifen, das den Fehler verursacht. -
StackTrace: Die
StackTraceEigenschaft enthält eine Stapelablaufverfolgung, die verwendet werden kann, um zu bestimmen, wo ein Fehler aufgetreten ist. -
TargetSite: Die
TargetSiteEigenschaft kann verwendet werden, um die Methode abzurufen, die die aktuelle Ausnahme auslöst.
Es ist in Ordnung, wenn Sie sich durch diese Untersuchung von Ausnahmeeigenschaften, Basisklassen und Vererbung etwas überwältigt fühlen. Machen Sie sich keine Sorgen, Ausnahmen in Ihrem Code abzufangen und auf die Eigenschaften einer Ausnahme zuzugreifen ist einfacher als zu erklären, wie Ausnahmen und ihre Eigenschaften funktionieren.
Hinweis
In diesem Modul konzentrieren Sie sich auf die Verwendung der Nachrichteneigenschaft einer Ausnahme, um die Ausnahme in der Benutzeroberfläche Ihrer Anwendung zu melden.
Zugreifen auf die Eigenschaften eines Ausnahmeobjekts
Nachdem Sie nun mit Ausnahmeobjekten und deren Eigenschaften vertraut sind, ist es an der Zeit, mit dem Codieren zu beginnen.
Aktualisieren Sie Ihre Program.cs Datei wie folgt:
try { Process1(); } catch { Console.WriteLine("An exception has occurred"); } Console.WriteLine("Exit program"); static void Process1() { try { WriteMessage(); } catch { Console.WriteLine("Exception caught in Process1"); } } static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); }Überprüfen Sie kurz den Code.
Dies ist derselbe Code, den Sie in der vorherigen Einheit (der Lösungscode für die Herausforderungsaktivität) gesehen haben. Sie wissen, dass während der
WriteMessageMethode eine Ausnahme ausgelöst wird. Sie wissen auch, dass die Ausnahme in derProcess1Methode abgefangen wird. Sie verwenden diesen Code, um Ausnahmeobjekte und bestimmte Ausnahmetypen zu untersuchen.Aktualisieren Sie die
Process1-Methode wie folgt:static void Process1() { try { WriteMessage(); } catch (Exception ex) { Console.WriteLine($"Exception caught in Process1: {ex.Message}"); } }Nehmen Sie sich eine Minute Zeit, um Ihre Aktualisierungen zu untersuchen.
Beachten Sie, dass ihre aktualisierte
catchKlausel eine Instanz derExceptionKlasse in einem Objekt namensexabfangen wird. Beachten Sie außerdem, dass IhreConsole.WriteLine()-Methodeexverwendet, um auf die Eigenschaft desMessage-Objekts zuzugreifen und die Fehlermeldung in der Konsole anzuzeigen.Obwohl die
catchKlausel ohne Argumente verwendet werden kann, wird dieser Ansatz nicht empfohlen. Wenn Sie kein Argument angeben, werden alle Ausnahmetypen abgefangen und Sie können nicht zwischen ihnen unterscheiden.Im Allgemeinen sollten Sie nur die Ausnahmen abfangen, die durch Ihren Code behandelt werden können. Daher sollte Ihre
catchKlausel ein Objektargument angeben, das vonSystem.Exceptionabgeleitet ist. Der Ausnahmetyp sollte so spezifisch wie möglich sein. Dies hilft, Ausnahmen zu vermeiden, die vom Ausnahmehandler nicht aufgelöst werden können. Sie aktualisieren Ihren Code, um einen bestimmten Ausnahmetyp später in dieser Übung abzufangen.Klicken Sie im Menü File (Datei) auf Save (Speichern).
Legen Sie den Haltepunkt in der folgenden Codezeile fest:
Console.WriteLine($"Exception caught in Process1: {ex.Message}");Wählen Sie im Menü "Ausführen" die Option "Debuggen starten" aus.
Die Codeausführung sollte am Haltepunkt angehalten werden.
Bewegen Sie den Mauszeiger über
ex.Beachten Sie, dass IntelliSense die gleichen Ausnahmeeigenschaften anzeigt, die Sie zuvor untersucht haben.
Nehmen Sie sich eine Minute Zeit, um die Informationen zu untersuchen, die das Ausnahmeobjekt
exbeschreiben.Beachten Sie, dass es sich um eine Ausnahme des Typs
System.DivideByZeroExceptionhandelt, und dass die EigenschaftMessageaufAttempted to divide by zero.festgelegt ist.Beachten Sie, dass die
StackTraceEigenschaft die Methode und die Zeilennummer meldet, an der der Fehler aufgetreten ist, sowie die Abfolge der Methodenaufrufe (und Zeilennummern), die zum Fehler geführt haben.Wählen Sie auf der Symbolleiste "Debuggen" die Option "Weiter" aus.
Nehmen Sie sich eine Minute Zeit, um die Konsolenausgabe zu untersuchen.
Beachten Sie, dass die Eigenschaft der
MessageAusnahme in der ausgabe enthalten ist, die von Ihrer Anwendung generiert wird:∞ Exception caught in Process1: Attempted to divide by zero. Exit program
Abfangen eines bestimmten Ausnahmetyps
Nachdem Sie nun den Typ der abzufangenden Ausnahme kennen, können Sie Ihre catch Klausel aktualisieren, um diesen bestimmten Ausnahmetyp zu behandeln.
Aktualisieren Sie die
Process1-Methode wie folgt:static void Process1() { try { WriteMessage(); } catch (DivideByZeroException ex) { Console.WriteLine($"Exception caught in Process1: {ex.Message}"); } }Speichern Sie Ihren Code, und starten Sie dann eine Debugsitzung.
Beachten Sie, dass ihre aktualisierte Anwendung die gleichen Nachrichten an der Konsole meldet.
Obwohl die gemeldeten Nachrichten identisch sind, gibt es einen wichtigen Unterschied. Ihre
Process1Methode erfasst nur Ausnahmen des spezifischen Typs, den sie verarbeiten kann.Um einen anderen Ausnahmetyp zu generieren, aktualisieren Sie die
WriteMessageMethode wie folgt:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; Console.WriteLine(float1 / float2); // Console.WriteLine(number1 / number2); checked { smallNumber = (byte)number1; } }Beachten Sie die Verwendung der
checked-Anweisung.Bei der Durchführung von Integraltypberechnungen, die den Wert eines integralen Typs einem anderen integralen Typ zuweisen, hängt das Ergebnis vom Überlaufüberprüfungskontext ab. In einem
checkedKontext ist die Konvertierung erfolgreich, wenn sich der Quellwert innerhalb des Bereichs des Zieltyps befindet. Andernfalls wird eineOverflowExceptionausgelöst. In einem deaktivierten Kontext ist die Konvertierung immer erfolgreich und wird wie folgt fortgesetzt:Wenn der Quelltyp größer als der Zieltyp ist, wird der Quellwert abgeschnitten, indem die wichtigsten "zusätzlichen" Bits verworfen werden. Das Ergebnis wird dann als Wert des Zieltyps behandelt.
Wenn der Quelltyp kleiner als der Zieltyp ist, ist der Quellwert entweder mit einem Vorzeichen oder einer Null erweitert, sodass er dieselbe Größe wie der Zieltyp aufweist. Vorzeichenerweiterung wird verwendet, wenn der Quelltyp ein Vorzeichen hat; Nullerweiterung wird verwendet, wenn der Quelltyp kein Vorzeichen hat. Das Ergebnis wird dann als Wert des Zieltyps behandelt.
Wenn der Quelltyp die gleiche Größe wie der Zieltyp aufweist, wird der Quellwert als Wert des Zieltyps behandelt.
Hinweis
Integrale Typberechnungen, die sich nicht innerhalb eines
checkedCodeblocks befinden, werden so behandelt, als ob sie sich in einemuncheckedCodeblock befinden.Speichern Sie Ihren Code, und starten Sie dann eine Debugsitzung.
Beachten Sie, dass ein neuer Ausnahmetyp nicht innerhalb der
catch-Methode, sondern durch dieProcess1-Klausel in den Anweisungen der obersten Ebene abgefangen wird.Ihre Anwendung druckt die folgenden Meldungen in der Konsole:
∞ An exception has occurred Exit programHinweis
Der
catchBlock inProcess1wird nicht ausgeführt. Dies ist das gewünschte Verhalten. Fangen Sie nur die Ausnahmen ab, auf deren Behandlung Ihr Code vorbereitet ist.
Abfangen mehrerer Ausnahmen in einem Codeblock
An diesem Punkt fragen Sie sich vielleicht, was passiert, wenn mehrere Ausnahmen in einem einzigen Codeblock auftreten. Fängt Ihr Code (über catch) jede Ausnahme bei deren Auftreten ab?
Aktualisieren Sie die
WriteMessage-Methode wie folgt:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); checked { smallNumber = (byte)number1; } }Platzieren Sie einen Haltepunkt innerhalb der
WriteMessage()-Methode in der folgenden Codezeile:Console.WriteLine(float1 / float2);Speichern Sie Ihren Code, und starten Sie dann eine Debugsitzung.
Durchlaufen Sie Schritt für Schritt Ihren Code, Zeile für Zeile, und beachten Sie dann, was passiert, nachdem der Code den ersten Ausnahmefall behandelt hat.
Wenn die erste Ausnahme auftritt, wird das Steuerelement an die erste
catchKlausel übergeben, die die Ausnahme behandeln kann. Der Code, der die zweite Ausnahme generiert, wird nie erreicht. Dies bedeutet, dass ein Teil des Codes nie ausgeführt wird. Dies könnte zu schwerwiegenden Problemen führen.Nehmen Sie sich eine Minute Zeit, um zu überlegen, wie Sie mehrere Ausnahmen verwalten können, und wann/warum Der Code möglicherweise nicht mehrere Ausnahmen verwalten soll.
Sie haben an früherer Stelle in diesem Modul gelernt, dass Ausnahmen möglichst nahe an dem Ort abgefangen werden sollten, an dem sie auftreten. Unter Berücksichtigung dieser Richtlinie können Sie die
WriteMessage-Methode aktualisieren, um Ausnahmen mit einer eigenentry-catch-Methode abzufangen. Beispiel:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; try { Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); } catch (DivideByZeroException ex) { Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}"); } checked { smallNumber = (byte)number1; } }Sie können auch den Code, der die
OverflowExceptionverursacht, in einer separatentry-catchinnerhalb derWriteMessage()-Methode umschließen.checked { try { smallNumber = (byte)number1; } catch (OverflowException ex) { Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}"); } }Unter welchen Bedingungen wäre es unerwünscht, nachfolgende Ausnahmen abzufangen?
Berücksichtigen Sie den Fall, wenn die Methode (oder der Codeblock) einen zweiteiligen Prozess abschließt. Gehen Sie davon aus, dass der zweite Teil des Prozesses vom abschluss des ersten Teils abhängig ist. Wenn der erste Teil des Prozesses nicht erfolgreich abgeschlossen werden kann, gibt es keinen Grund, den zweiten Teil des Prozesses fortzusetzen. In diesem Fall ist es häufig besser, dem Benutzer eine Meldung zu präsentieren, in der die Fehlerbedingung erläutert wird, ohne die verbleibenden Teile oder Teile des größeren Prozesses zu versuchen.
Abfangen verschiedener Ausnahmetypen in einem Codeblock
Es gibt Zeiten, in denen Variationen in Ihren Daten verschiedene Arten von Ausnahmen verursachen können.
Löschen Sie Ihre Haltepunkte, und ersetzen Sie dann den Inhalt der „Datei Program.cs“ durch den folgenden Code:
// inputValues is used to store numeric values entered by a user string[] inputValues = new string[]{"three", "9999999999", "0", "2" }; foreach (string inputValue in inputValues) { int numValue = 0; try { numValue = int.Parse(inputValue); } catch (FormatException) { Console.WriteLine("Invalid readResult. Please enter a valid number."); } catch (OverflowException) { Console.WriteLine("The number you entered is too large or too small."); } catch(Exception ex) { Console.WriteLine(ex.Message); } }Nehmen Sie sich eine Minute Zeit, um diesen Code zu überprüfen.
Zunächst erstellt der Code ein Zeichenfolgenarray mit dem Namen
inputValues. Die Daten im Array sollen die Eingabewerte darstellen, die von einem Benutzer eingegeben wurden, der angewiesen wurde, numerische Werte einzugeben. Je nach eingegebenen Wert können unterschiedliche Ausnahmetypen auftreten.Beachten Sie, dass der Code die
int.ParseMethode verwendet, um die Zeichenfolgenwerte "eingabe" in ganze Zahlen zu konvertieren. Derint.ParseCode wird in einemtryCodeblock platziert.Legen Sie einen Haltepunkt in der folgenden Codezeile fest:
int numValue = 0;Speichern Sie Ihren Code, und starten Sie dann eine Debugsitzung.
Gehen Sie den Code Zeile für Zeile durch, und beachten Sie, dass verschiedene Ausnahmetypen abgefangen werden.
Zusammenfassung
Nachstehend finden Sie nochmals die wichtigsten Punkte aus dieser Lerneinheit:
- Die
catchKlausel sollte so konfiguriert werden, dass ein bestimmter Ausnahmetyp erfasst wird. Beispielsweise derDivideByZeroExceptionAusnahmetyp. - Auf die Eigenschaften eines Ausnahmeobjekts kann innerhalb des
catchBlocks zugegriffen werden. Sie können beispielsweise dieMessageEigenschaft verwenden, um den Anwendungsbenutzer über ein Problem zu informieren. - Sie können zwei oder mehr
catchKlauseln angeben, wenn Sie mehrere Ausnahmetypen erfassen müssen.