Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Dieser Artikel enthält ergänzende Hinweise zur Referenzdokumentation für diese API.
Die Exception Klasse ist die Basisklasse für alle Ausnahmen. Wenn ein Fehler auftritt, meldet das System oder die aktuell ausgeführte Anwendung sie, indem eine Ausnahme ausgelöst wird, die Informationen zum Fehler enthält. Nachdem eine Ausnahme ausgelöst wurde, wird sie von der Anwendung oder vom Standardmäßigen Ausnahmehandler behandelt.
Fehler und Ausnahmen
Laufzeitfehler können aus verschiedenen Gründen auftreten. Nicht alle Fehler sollten jedoch als Ausnahmen in Ihrem Code behandelt werden. Im Folgenden finden Sie einige Kategorien von Fehlern, die zur Laufzeit auftreten können, und die geeigneten Möglichkeiten, auf sie zu reagieren.
Verwendungsfehler. Ein Verwendungsfehler stellt einen Fehler in der Programmlogik dar, der zu einer Ausnahme führen kann. Der Fehler sollte jedoch nicht durch die Ausnahmebehandlung behoben werden, sondern durch Ändern des fehlerhaften Codes. Die Außerkraftsetzung der Object.Equals(Object) Methode im folgenden Beispiel geht davon aus, dass das
objArgument immer nicht null sein muss.using System; public class Person1 { private string _name; public string Name { get { return _name; } set { _name = value; } } public override int GetHashCode() { return this.Name.GetHashCode(); } public override bool Equals(object obj) { // This implementation contains an error in program logic: // It assumes that the obj argument is not null. Person1 p = (Person1) obj; return this.Name.Equals(p.Name); } } public class UsageErrorsEx1 { public static void Main() { Person1 p1 = new Person1(); p1.Name = "John"; Person1 p2 = null; // The following throws a NullReferenceException. Console.WriteLine($"p1 = p2: {p1.Equals(p2)}"); } }// In F#, null is not a valid state for declared types // without 'AllowNullLiteralAttribute' [<AllowNullLiteral>] type Person() = member val Name = "" with get, set override this.GetHashCode() = this.Name.GetHashCode() override this.Equals(obj) = // This implementation contains an error in program logic: // It assumes that the obj argument is not null. let p = obj :?> Person this.Name.Equals p.Name let p1 = Person() p1.Name <- "John" let p2: Person = null // The following throws a NullReferenceException. printfn $"p1 = p2: {p1.Equals p2}"Public Class Person Private _name As String Public Property Name As String Get Return _name End Get Set _name = value End Set End Property Public Overrides Function Equals(obj As Object) As Boolean ' This implementation contains an error in program logic: ' It assumes that the obj argument is not null. Dim p As Person = CType(obj, Person) Return Me.Name.Equals(p.Name) End Function End Class Module Example2 Public Sub Main() Dim p1 As New Person() p1.Name = "John" Dim p2 As Person = Nothing ' The following throws a NullReferenceException. Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)) End Sub End ModuleDie NullReferenceException-Ausnahme, die entsteht, wenn
objgleichnullist, kann vermieden werden, indem Sie den Quellcode so ändern, dass er explizit auf NULL testet, bevor die Object.Equals-Außerkraftsetzung aufgerufen wird, und der Code dann erneut kompiliert wird. Das folgende Beispiel enthält den korrigierten Quellcode, der einnullArgument behandelt.using System; public class Person2 { private string _name; public string Name { get { return _name; } set { _name = value; } } public override int GetHashCode() { return this.Name.GetHashCode(); } public override bool Equals(object obj) { // This implementation handles a null obj argument. Person2 p = obj as Person2; if (p == null) return false; else return this.Name.Equals(p.Name); } } public class UsageErrorsEx2 { public static void Main() { Person2 p1 = new Person2(); p1.Name = "John"; Person2 p2 = null; Console.WriteLine($"p1 = p2: {p1.Equals(p2)}"); } } // The example displays the following output: // p1 = p2: False// In F#, null is not a valid state for declared types // without 'AllowNullLiteralAttribute' [<AllowNullLiteral>] type Person() = member val Name = "" with get, set override this.GetHashCode() = this.Name.GetHashCode() override this.Equals(obj) = // This implementation handles a null obj argument. match obj with | :? Person as p -> this.Name.Equals p.Name | _ -> false let p1 = Person() p1.Name <- "John" let p2: Person = null printfn $"p1 = p2: {p1.Equals p2}" // The example displays the following output: // p1 = p2: FalsePublic Class Person2 Private _name As String Public Property Name As String Get Return _name End Get Set _name = Value End Set End Property Public Overrides Function Equals(obj As Object) As Boolean ' This implementation handles a null obj argument. Dim p As Person2 = TryCast(obj, Person2) If p Is Nothing Then Return False Else Return Me.Name.Equals(p.Name) End If End Function End Class Module Example3 Public Sub Main() Dim p1 As New Person2() p1.Name = "John" Dim p2 As Person2 = Nothing Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)) End Sub End Module ' The example displays the following output: ' p1 = p2: FalseAnstatt die Ausnahmebehandlung für Verwendungsfehler zu verwenden, können Sie die Debug.Assert Methode verwenden, um Verwendungsfehler in Debugbuilds zu identifizieren, und die Trace.Assert Methode zum Identifizieren von Verwendungsfehlern in Debug- und Releasebuilds. Weitere Informationen finden Sie unter Assertionen in verwaltetem Code.
Programmfehler. Ein Programmfehler ist ein Laufzeitfehler, der nicht unbedingt vermieden werden kann, indem fehlerfreier Code geschrieben wird.
In einigen Fällen kann ein Programmfehler eine erwartete oder Routinefehlerbedingung widerspiegeln. In diesem Fall sollten Sie die Verwendung der Ausnahmebehandlung vermeiden, um den Programmfehler zu behandeln, und versuchen Sie stattdessen den Vorgang erneut. Wenn beispielsweise erwartet wird, dass der Benutzer ein Datum in einem bestimmten Format eingibt, können Sie die Datumszeichenfolge analysieren, indem Sie die Methode aufrufen, die DateTime.TryParseExact einen Boolean Wert zurückgibt, der angibt, ob der Analysevorgang erfolgreich war, anstatt die DateTime.ParseExact Methode zu verwenden, die eine FormatException Ausnahme auslöst, wenn die Datumszeichenfolge nicht in einen DateTime Wert konvertiert werden kann. Wenn ein Benutzer versucht, eine datei zu öffnen, die nicht vorhanden ist, können Sie zuerst die File.Exists Methode aufrufen, um zu überprüfen, ob die Datei vorhanden ist. Wenn dies nicht der Fall ist, wird der Benutzer gefragt, ob er sie erstellen möchte.
In anderen Fällen spiegelt ein Programmfehler eine unerwartete Fehlerbedingung wider, die in Ihrem Code behandelt werden kann. Selbst wenn Sie überprüft haben, ob eine Datei vorhanden ist, kann sie gelöscht werden, bevor Sie sie öffnen können, oder sie ist beschädigt. In diesem Fall wird beim Versuch, die Datei zu öffnen, durch Instanziieren eines StreamReader Objekts oder Aufrufen der Open Methode eine FileNotFoundException Ausnahme ausgelöst. In diesen Fällen sollten Sie die Ausnahmebehandlung verwenden, um sich vom Fehler zu erholen.
Systemfehler. Ein Systemfehler ist ein Laufzeitfehler, der nicht programmgesteuert auf sinnvolle Weise behandelt werden kann. Beispielsweise kann jede Methode eine OutOfMemoryException Ausnahme auslösen, wenn die Common Language Runtime keinen zusätzlichen Arbeitsspeicher zuweisen kann. In der Regel werden Systemfehler nicht mithilfe der Ausnahmebehandlung behandelt. Stattdessen können Sie möglicherweise ein Ereignis wie AppDomain.UnhandledException verwenden und die Environment.FailFast Methode aufrufen, um Ausnahmeinformationen zu protokollieren und den Benutzer über den Fehler zu benachrichtigen, bevor die Anwendung beendet wird.
try/catch-Blöcke
Die Common Language Runtime stellt ein Ausnahmebehandlungsmodell bereit, das auf der Darstellung von Ausnahmen als Objekte basiert, und die Trennung von Programmcode und Ausnahmebehandlungscode in try Blöcke und catch Blöcke. Es kann eine oder catch mehrere Blöcke geben, die jeweils für die Behandlung eines bestimmten Ausnahmetyps konzipiert sind, oder ein Block, der eine spezifischere Ausnahme als einen anderen Block abfangen soll.
Wenn eine Anwendung Ausnahmen verarbeitet, die während der Ausführung eines Anwendungscodes auftreten, muss der Code in einer try Anweisung platziert und als try Block bezeichnet werden. Anwendungscode, der Ausnahmen behandelt, die von einem try Block ausgelöst werden, wird in einer catch Anweisung platziert und als Block bezeichnet catch . Null oder mehr catch Blöcke sind einem try Block zugeordnet, und jeder catch Block enthält einen Typfilter, der die Typen der behandelten Ausnahmen bestimmt.
Wenn eine Ausnahme in einem try Block auftritt, durchsucht das System die zugehörigen catch Blöcke in der Reihenfolge, in der sie im Anwendungscode angezeigt werden, bis ein catch Block gefunden wird, der die Ausnahme behandelt. Ein catch-Block behandelt eine Ausnahme vom Typ T, wenn der Typfilter des Catch-Blocks T oder einen Typ angibt, von dem T abgeleitet wird. Das System beendet die Suche, nachdem der erste catch Block gefunden wurde, der die Ausnahme behandelt. Aus diesem Grund muss im Anwendungscode ein catch Block, der einen Typ behandelt, vor einem catch Block angegeben werden, der seine Basistypen behandelt, wie im beispiel, das auf diesen Abschnitt folgt. Ein Catch-Block, der System.Exception behandelt, wird zuletzt angegeben.
Wenn keiner der catch Blöcke, die dem aktuellen try Block zugeordnet sind, die Ausnahme behandelt und der aktuelle try Block innerhalb anderer try Blöcke im aktuellen Aufruf geschachtelt ist, werden die catch Blöcke, die dem nächsten umgebenden try Block zugeordnet sind, durchsucht. Wenn kein catch-Block für die Ausnahme gefunden wird, durchsucht das System vorherige Schachtelungsebenen im aktuellen Aufruf. Wenn im aktuellen Aufruf kein catch Block für die Ausnahme gefunden wird, dann wird die Ausnahme entlang der Methodenaufrufkette nach oben weitergereicht, und der vorherige Stackframe wird nach einem catch Block durchsucht, der die Ausnahme behandelt. Die Suche des Aufrufstapels wird fortgesetzt, bis die Ausnahme behandelt wird oder bis keine weiteren Frames im Aufrufstapel vorhanden sind. Wenn der obere Rand des Aufrufstapels erreicht ist, ohne einen catch Block zu finden, der die Ausnahme behandelt, behandelt der Standard ausnahmehandler sie und die Anwendung wird beendet.
try..with-Ausdruck (F#)
F# verwendet keine catch-Blöcke. Stattdessen wird eine ausgelöste Ausnahme mit einem einzelnen with-Block abgeglichen. Da es sich um einen Ausdruck anstelle einer Anweisung handelt, müssen alle Pfade denselben Typ zurückgeben. Weitere Informationen finden Sie unter try...with-Ausdruck.
Eigenschaften von Ausnahmetypen
Ausnahmetypen unterstützen die folgenden Features:
Lesbarer Text, der den Fehler beschreibt. Wenn eine Ausnahme auftritt, stellt die Laufzeit eine Textnachricht zur Verfügung, um den Benutzer über die Art des Fehlers zu informieren und maßnahmen zur Behebung des Problems vorzuschlagen. Diese Textnachricht wird in der Message Eigenschaft des Ausnahmeobjekts gespeichert. Beim Erstellen des Ausnahmeobjekts können Sie eine Textzeichenfolge an den Konstruktor übergeben, um die Details dieser bestimmten Ausnahme zu beschreiben. Wenn dem Konstruktor kein Fehlermeldungsargument bereitgestellt wird, wird die Standardfehlermeldung verwendet. Weitere Informationen finden Sie in den Ausführungen zur Message-Eigenschaft.
Der Status des Aufrufstapels, als die Ausnahme ausgelöst wurde: Die StackTrace Eigenschaft enthält eine Stapelablaufverfolgung, die verwendet werden kann, um zu bestimmen, wo der Fehler im Code auftritt. Die Stapelablaufverfolgung listet alle aufgerufenen Methoden und die Zeilennummern in der Quelldatei auf, in der die Aufrufe getätigt werden.
Ausnahmeklasseneigenschaften
Die Exception Klasse enthält eine Reihe von Eigenschaften, die helfen, den Codespeicherort, den Typ, die Hilfedatei und den Grund für die Ausnahme zu identifizieren: StackTrace, InnerException, Message, HelpLink, HResult, Source, TargetSite und Data.
Wenn eine kausale Beziehung zwischen zwei oder mehr Ausnahmen besteht, verwaltet die InnerException Eigenschaft diese Informationen. Die äußere Ausnahme wird als Reaktion auf diese innere Ausnahme ausgelöst. Der Code, der die äußere Ausnahme behandelt, kann die Informationen aus der früheren inneren Ausnahme verwenden, um den Fehler besser zu behandeln. Ergänzende Informationen zur Ausnahme können als Sammlung von Schlüssel-Wert-Paaren in der Data Eigenschaft gespeichert werden.
Die Fehlermeldungszeichenfolge, die während der Erstellung des Ausnahmeobjekts an den Konstruktor übergeben wird, sollte lokalisiert werden und kann mithilfe der ResourceManager Klasse aus einer Ressourcendatei bereitgestellt werden. Weitere Informationen zu lokalisierten Ressourcen finden Sie in den Themen Erstellen von Satellitenassemblys und Verpacken und Bereitstellen von Ressourcen.
Um dem Benutzer umfangreiche Informationen darüber bereitzustellen, warum die Ausnahme aufgetreten ist, kann die HelpLink Eigenschaft eine URL (oder URN) zu einer Hilfedatei enthalten.
Die Exception Klasse verwendet das HRESULT COR_E_EXCEPTION, das den Wert 0x80131500 hat.
Eine Liste der anfänglichen Eigenschaftswerte für eine Instanz der Exception Klasse finden Sie in den Exception Konstruktoren.
Leistungsüberlegungen
Das Auslösen oder Behandeln einer Ausnahme verbraucht eine erhebliche Menge an Systemressourcen und Ausführungszeit. Lösen Sie Ausnahmen nur aus, um wirklich außergewöhnliche Bedingungen zu verarbeiten, nicht um vorhersehbare Ereignisse oder Flusssteuerungen zu behandeln. In einigen Fällen, z. B. beim Entwickeln einer Klassenbibliothek, ist es sinnvoll, eine Ausnahme auszuwerfen, wenn ein Methodenargument ungültig ist, da Sie erwarten, dass die Methode mit gültigen Parametern aufgerufen wird. Ein ungültiges Methodenargument, wenn es nicht das Ergebnis eines Verwendungsfehlers ist, bedeutet, dass etwas Außergewöhnliches aufgetreten ist. Lösen Sie dagegen keine Ausnahme aus, wenn die Benutzereingabe ungültig ist, da Sie erwarten können, dass Benutzer gelegentlich ungültige Daten eingeben. Stellen Sie stattdessen einen Wiederholungsmechanismus bereit, damit Benutzer gültige Eingaben eingeben können. Sie sollten auch keine Ausnahmen verwenden, um Verwendungsfehler zu behandeln. Verwenden Sie stattdessen Assertionen , um Verwendungsfehler zu identifizieren und zu korrigieren.
Werfen Sie darüber hinaus keine Ausnahme, wenn ein Rückgabecode ausreichend ist; konvertieren Sie keinen Rückgabecode in eine Ausnahme; und fangen Sie nicht routinemäßig eine Ausnahme ab, ignorieren Sie sie nicht und fahren Sie dann mit der Verarbeitung fort.
Erneutes Auslösen einer Ausnahme
In vielen Fällen möchte ein Ausnahmehandler einfach die Ausnahme an den Aufrufer übergeben. Dies geschieht am häufigsten in:
Eine Klassenbibliothek, die wiederum Aufrufe von Methoden in der .NET-Klassenbibliothek oder anderen Klassenbibliotheken umschließt.
Eine Anwendung oder Bibliothek, die auf eine schwerwiegende Ausnahme stößt. Der Ausnahmehandler kann die Ausnahme protokollieren und dann die Ausnahme erneut auslösen.
Die empfohlene Methode zum erneuten Auslösen einer Ausnahme besteht darin, einfach die Throw-Anweisung in C#, die Funktion " Reraise" in F# und die Throw-Anweisung in Visual Basic zu verwenden, ohne einen Ausdruck einzuschlussen. Dadurch wird sichergestellt, dass alle Aufrufstapelinformationen beibehalten werden, wenn die Ausnahme an den Aufrufer weitergegeben wird. Im folgenden Beispiel wird dies veranschaulicht. Eine Zeichenfolgenerweiterungsmethode FindOccurrences umschließt ein oder mehrere Aufrufe von String.IndexOf(String, Int32), ohne die Argumente vorher zu validieren.
using System;
using System.Collections.Generic;
public static class Library1
{
public static int[] FindOccurrences(this String s, String f)
{
var indexes = new List<int>();
int currentIndex = 0;
try
{
while (currentIndex >= 0 && currentIndex < s.Length)
{
currentIndex = s.IndexOf(f, currentIndex);
if (currentIndex >= 0)
{
indexes.Add(currentIndex);
currentIndex++;
}
}
}
catch (ArgumentNullException)
{
// Perform some action here, such as logging this exception.
throw;
}
return indexes.ToArray();
}
}
open System
module Library =
let findOccurrences (s: string) (f: string) =
let indexes = ResizeArray()
let mutable currentIndex = 0
try
while currentIndex >= 0 && currentIndex < s.Length do
currentIndex <- s.IndexOf(f, currentIndex)
if currentIndex >= 0 then
indexes.Add currentIndex
currentIndex <- currentIndex + 1
with :? ArgumentNullException ->
// Perform some action here, such as logging this exception.
reraise ()
indexes.ToArray()
Imports System.Collections.Generic
Imports System.Runtime.CompilerServices
Public Module Library
<Extension()>
Public Function FindOccurrences1(s As String, f As String) As Integer()
Dim indexes As New List(Of Integer)
Dim currentIndex As Integer = 0
Try
Do While currentIndex >= 0 And currentIndex < s.Length
currentIndex = s.IndexOf(f, currentIndex)
If currentIndex >= 0 Then
indexes.Add(currentIndex)
currentIndex += 1
End If
Loop
Catch e As ArgumentNullException
' Perform some action here, such as logging this exception.
Throw
End Try
Return indexes.ToArray()
End Function
End Module
Ein Anrufer ruft dann zweimal auf FindOccurrences . Im zweiten Aufruf an FindOccurrences, übergibt der Aufrufer eine null als Suchzeichenfolge, wodurch die String.IndexOf(String, Int32) Methode eine ArgumentNullException Ausnahme auslöst. Diese Ausnahme wird von der FindOccurrences Methode behandelt und an den Aufrufer übergeben. Da die throw-Anweisung ohne Ausdruck verwendet wird, zeigt die Ausgabe des Beispiels, dass der Aufrufstapel erhalten bleibt.
public class RethrowEx1
{
public static void Main()
{
String s = "It was a cold day when...";
int[] indexes = s.FindOccurrences("a");
ShowOccurrences(s, "a", indexes);
Console.WriteLine();
String toFind = null;
try
{
indexes = s.FindOccurrences(toFind);
ShowOccurrences(s, toFind, indexes);
}
catch (ArgumentNullException e)
{
Console.WriteLine($"An exception ({e.GetType().Name}) occurred.");
Console.WriteLine($"Message:{Environment.NewLine} {e.Message}{Environment.NewLine}");
Console.WriteLine($"Stack Trace:{Environment.NewLine} {e.StackTrace}{Environment.NewLine}");
}
}
private static void ShowOccurrences(String s, String toFind, int[] indexes)
{
Console.Write("'{0}' occurs at the following character positions: ",
toFind);
for (int ctr = 0; ctr < indexes.Length; ctr++)
Console.Write("{0}{1}", indexes[ctr],
ctr == indexes.Length - 1 ? "" : ", ");
Console.WriteLine();
}
}
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message:
// Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
open Library
let showOccurrences toFind (indexes: int[]) =
printf $"'{toFind}' occurs at the following character positions: "
for i = 0 to indexes.Length - 1 do
printf $"""{indexes[i]}{if i = indexes.Length - 1 then "" else ", "}"""
printfn ""
let s = "It was a cold day when..."
let indexes = findOccurrences s "a"
showOccurrences "a" indexes
printfn ""
let toFind: string = null
try
let indexes = findOccurrences s toFind
showOccurrences toFind indexes
with :? ArgumentNullException as e ->
printfn $"An exception ({e.GetType().Name}) occurred."
printfn $"Message:\n {e.Message}\n"
printfn $"Stack Trace:\n {e.StackTrace}\n"
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message:
// Value cannot be null. (Parameter 'value')
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.findOccurrences(String s, String f)
// at <StartupCode$fs>.main@()
Module Example1
Public Sub Main()
Dim s As String = "It was a cold day when..."
Dim indexes() As Integer = s.FindOccurrences1("a")
ShowOccurrences(s, "a", indexes)
Console.WriteLine()
Dim toFind As String = Nothing
Try
indexes = s.FindOccurrences1(toFind)
ShowOccurrences(s, toFind, indexes)
Catch e As ArgumentNullException
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name)
Console.WriteLine("Message:{0} {1}{0}", vbCrLf, e.Message)
Console.WriteLine("Stack Trace:{0} {1}{0}", vbCrLf, e.StackTrace)
End Try
End Sub
Private Sub ShowOccurrences(s As String, toFind As String, indexes As Integer())
Console.Write("'{0}' occurs at the following character positions: ",
toFind)
For ctr As Integer = 0 To indexes.Length - 1
Console.Write("{0}{1}", indexes(ctr),
If(ctr = indexes.Length - 1, "", ", "))
Next
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' 'a' occurs at the following character positions: 4, 7, 15
'
' An exception (ArgumentNullException) occurred.
' Message:
' Value cannot be null.
' Parameter name: value
'
' Stack Trace:
' at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
' ngComparison comparisonType)
' at Library.FindOccurrences(String s, String f)
' at Example.Main()
Wenn die Ausnahme jedoch mithilfe dieser Anweisung erneut ausgelöst wird:
throw e;
Throw e
raise e
... dann wird der vollständige Aufrufstapel nicht beibehalten, und das Beispiel würde die folgende Ausgabe generieren:
'a' occurs at the following character positions: 4, 7, 15
An exception (ArgumentNullException) occurred.
Message:
Value cannot be null.
Parameter name: value
Stack Trace:
at Library.FindOccurrences(String s, String f)
at Example.Main()
Eine etwas umständlichere Alternative besteht darin, eine neue Ausnahme auszulösen und die Informationen zur Aufrufliste der ursprünglichen Ausnahme in einer inneren Ausnahme beizubehalten. Der Anrufer kann dann die Eigenschaft der neuen Ausnahme InnerException verwenden, um Stack-Frame und andere Informationen der ursprünglichen Ausnahme abzurufen. In diesem Fall lautet die throw-Anweisung:
throw new ArgumentNullException("You must supply a search string.", e);
raise (ArgumentNullException("You must supply a search string.", e) )
Throw New ArgumentNullException("You must supply a search string.",
e)
Der Benutzercode, der die Ausnahme behandelt, muss wissen, dass die InnerException Eigenschaft Informationen zur ursprünglichen Ausnahme enthält, wie der folgende Ausnahmehandler veranschaulicht.
try
{
indexes = s.FindOccurrences(toFind);
ShowOccurrences(s, toFind, indexes);
}
catch (ArgumentNullException e)
{
Console.WriteLine($"An exception ({e.GetType().Name}) occurred.");
Console.WriteLine($" Message:{Environment.NewLine}{e.Message}");
Console.WriteLine($" Stack Trace:{Environment.NewLine} {e.StackTrace}");
Exception ie = e.InnerException;
if (ie != null)
{
Console.WriteLine(" The Inner Exception:");
Console.WriteLine($" Exception Name: {ie.GetType().Name}");
Console.WriteLine($" Message: {ie.Message}{Environment.NewLine}");
Console.WriteLine($" Stack Trace:{Environment.NewLine} {ie.StackTrace}{Environment.NewLine}");
}
}
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message: You must supply a search string.
//
// Stack Trace:
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
//
// The Inner Exception:
// Exception Name: ArgumentNullException
// Message: Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
try
let indexes = findOccurrences s toFind
showOccurrences toFind indexes
with :? ArgumentNullException as e ->
printfn $"An exception ({e.GetType().Name}) occurred."
printfn $" Message:\n{e.Message}"
printfn $" Stack Trace:\n {e.StackTrace}"
let ie = e.InnerException
if ie <> null then
printfn " The Inner Exception:"
printfn $" Exception Name: {ie.GetType().Name}"
printfn $" Message: {ie.Message}\n"
printfn $" Stack Trace:\n {ie.StackTrace}\n"
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message: You must supply a search string.
//
// Stack Trace:
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
//
// The Inner Exception:
// Exception Name: ArgumentNullException
// Message: Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
Try
indexes = s.FindOccurrences(toFind)
ShowOccurrences(s, toFind, indexes)
Catch e As ArgumentNullException
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name)
Console.WriteLine(" Message: {1}{0}", vbCrLf, e.Message)
Console.WriteLine(" Stack Trace:{0} {1}{0}", vbCrLf, e.StackTrace)
Dim ie As Exception = e.InnerException
If ie IsNot Nothing Then
Console.WriteLine(" The Inner Exception:")
Console.WriteLine(" Exception Name: {0}", ie.GetType().Name)
Console.WriteLine(" Message: {1}{0}", vbCrLf, ie.Message)
Console.WriteLine(" Stack Trace:{0} {1}{0}", vbCrLf, ie.StackTrace)
End If
End Try
' The example displays the following output:
' 'a' occurs at the following character positions: 4, 7, 15
'
' An exception (ArgumentNullException) occurred.
' Message: You must supply a search string.
'
' Stack Trace:
' at Library.FindOccurrences(String s, String f)
' at Example.Main()
'
' The Inner Exception:
' Exception Name: ArgumentNullException
' Message: Value cannot be null.
' Parameter name: value
'
' Stack Trace:
' at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
' ngComparison comparisonType)
' at Library.FindOccurrences(String s, String f)
Auswählen von Standard ausnahmen
Wenn Sie eine Ausnahme auslösen müssen, können Sie häufig einen vorhandenen Ausnahmetyp in .NET verwenden, anstatt eine benutzerdefinierte Ausnahme zu implementieren. Sie sollten unter diesen beiden Bedingungen einen Standard-Ausnahmetyp verwenden:
Sie lösen eine Ausnahme aus, die durch einen Verwendungsfehler verursacht wird (d. a. durch einen Fehler in der Programmlogik des Entwicklers, der Ihre Methode aufruft). In der Regel würden Sie eine Ausnahme auslösen, wie z. B. ArgumentException, ArgumentNullException, InvalidOperationException oder NotSupportedException. Die Zeichenfolge, die Sie beim Instanziieren des Ausnahmeobjekts für den Konstruktor des Ausnahmeobjekts angeben, sollte den Fehler beschreiben, damit der Entwickler ihn beheben kann. Weitere Informationen finden Sie in den Ausführungen zur Message-Eigenschaft.
Sie behandeln einen Fehler, der dem Aufrufer mit einer vorhandenen .NET-Ausnahme mitgeteilt werden kann. Sie sollten die am häufigsten abgeleitete Ausnahme auslösen. Wenn eine Methode zum Beispiel ein Argument als gültiges Element eines Enumerationstyps erfordert, sollten Sie eine InvalidEnumArgumentException (die am weitesten abgeleitete Klasse) anstelle einer ArgumentException werfen.
In der folgenden Tabelle sind allgemeine Ausnahmetypen und die Bedingungen aufgeführt, unter denen Sie sie auslösen würden.
| Ausnahme | Zustand |
|---|---|
| ArgumentException | Ein Nicht-Null-Argument, das an eine Methode übergeben wird, ist ungültig. |
| ArgumentNullException | Ein Argument, das an eine Methode übergeben wird, ist null. |
| ArgumentOutOfRangeException | Ein Argument liegt außerhalb des Bereichs gültiger Werte. |
| DirectoryNotFoundException | Ein Teil eines Verzeichnispfads ist ungültig. |
| DivideByZeroException | Der Nenner in einer ganzen Zahl oder Decimal einem Divisionsvorgang ist Null. |
| DriveNotFoundException | Ein Laufwerk ist nicht verfügbar oder nicht vorhanden. |
| FileNotFoundException | Eine Datei ist nicht vorhanden. |
| FormatException | Ein Wert befindet sich nicht in einem geeigneten Format, um von einer Zeichenfolge durch eine Konvertierungsmethode wie z. B. Parse konvertiert zu werden. |
| IndexOutOfRangeException | Ein Index liegt außerhalb der Grenzen eines Arrays oder einer Auflistung. |
| InvalidOperationException | Ein Methodenaufruf ist im aktuellen Zustand eines Objekts ungültig. |
| KeyNotFoundException | Der angegebene Schlüssel für den Zugriff auf ein Element in einer Auflistung kann nicht gefunden werden. |
| NotImplementedException | Eine Methode oder ein Vorgang ist nicht implementiert. |
| NotSupportedException | Eine Methode oder ein Vorgang wird nicht unterstützt. |
| ObjectDisposedException | Ein Vorgang wird für ein Objekt ausgeführt, das verworfen wurde. |
| OverflowException | Ein arithmetischer, Umwandlungs- oder Konvertierungsvorgang führt zu einem Überlauf. |
| PathTooLongException | Ein Pfad oder Dateiname überschreitet die maximale systemdefinierte Länge. |
| PlatformNotSupportedException | Der Vorgang wird auf der aktuellen Plattform nicht unterstützt. |
| RankException | Ein Array mit der falschen Anzahl von Dimensionen wird an eine Methode übergeben. |
| TimeoutException | Das zeitintervall, das einem Vorgang zugewiesen ist, ist abgelaufen. |
| UriFormatException | Es wird ein ungültiger URI (Uniform Resource Identifier) verwendet. |
Implementieren von benutzerdefinierten Ausnahmen
In den folgenden Fällen ist die Verwendung einer vorhandenen .NET-Ausnahme zur Behandlung einer Fehlerbedingung nicht ausreichend:
Wenn die Ausnahme einen eindeutigen Programmfehler widerspiegelt, der einer vorhandenen .NET-Ausnahme nicht zugeordnet werden kann.
Wenn für die Ausnahme eine Behandlung erforderlich ist, die sich von der Behandlung unterscheidet, die für eine vorhandene .NET-Ausnahme geeignet ist, oder die Ausnahme muss von einer ähnlichen Ausnahme getrennt werden. Wenn Sie beispielsweise beim Analysieren der numerischen Darstellung einer Zeichenfolge, die außerhalb des Bereichs des Integraltyps des Zieles liegt, eine ArgumentOutOfRangeException Ausnahme auslösen, sollten Sie nicht dieselbe Ausnahme für einen Fehler verwenden, der daraus resultiert, dass der Aufrufer nicht die passenden eingeschränkten Werte bereitstellt, wenn er die Methode aufruft.
Die Exception Klasse ist die Basisklasse aller Ausnahmen in .NET. Viele abgeleitete Klassen basieren auf dem geerbten Verhalten der Member der Exception Klasse. Sie überschreiben weder die Member von Exceptionnoch definieren sie eindeutige Member.
So definieren Sie Ihre eigene Ausnahmeklasse:
Definieren Sie eine Klasse, die von Exception erbt. Definieren Sie bei Bedarf alle eindeutigen Member, die von Ihrer Klasse benötigt werden, um zusätzliche Informationen zur Ausnahme anzugeben. Die Klasse enthält beispielsweise eine ArgumentException Eigenschaft, die den Namen des Parameters angibt, ParamName dessen Argument die Ausnahme verursacht hat, und die RegexMatchTimeoutException Eigenschaft enthält eine MatchTimeout Eigenschaft, die das Timeoutintervall angibt.
Bei Bedarf setzen Sie geerbte Mitglieder außer Kraft, deren Funktionalität Sie ändern oder modifizieren möchten. Beachten Sie, dass die meisten vorhandenen abgeleiteten Klassen von Exception das Verhalten von geerbten Membern nicht außer Kraft setzen.
Bestimmen Sie, ob ihr benutzerdefiniertes Ausnahmeobjekt serialisierbar ist. Mithilfe der Serialisierung können Sie Informationen über die Ausnahme speichern und zulassen, dass Ausnahmeinformationen von einem Server und einem Clientproxy in einem Remotingkontext freigegeben werden. Um das Ausnahmeobjekt serialisierbar zu machen, markieren Sie es mit dem SerializableAttribute Attribut.
Definieren Sie die Konstruktoren Ihrer Ausnahmeklasse. In der Regel verfügen Ausnahmeklassen über einen oder mehrere der folgenden Konstruktoren:
Exception(), die Standardwerte verwendet, um die Eigenschaften eines neuen Ausnahmeobjekts zu initialisieren.
Exception(String), das ein neues Ausnahmeobjekt mit einer angegebenen Fehlermeldung initialisiert.
Exception(String, Exception), das ein neues Ausnahmeobjekt mit einer angegebenen Fehlermeldung und einer inneren Ausnahme initialisiert.
Exception(SerializationInfo, StreamingContext), bei dem es sich um einen
protectedKonstruktor handelt, der ein neues Ausnahmeobjekt aus serialisierten Daten initialisiert. Sie sollten diesen Konstruktor implementieren, wenn Sie sich entschieden haben, das Ausnahmeobjekt serialisierbar zu machen.
Das folgende Beispiel veranschaulicht die Verwendung einer benutzerdefinierten Ausnahmeklasse. Sie definiert eine NotPrimeException Ausnahme, die ausgelöst wird, wenn ein Client versucht, eine Abfolge von Primzahlen abzurufen, indem eine Anfangsnummer angegeben wird, die nicht Primzahl ist. Die Ausnahme definiert eine neue Eigenschaft, NonPrimedie die Nicht-Primzahl zurückgibt, die die Ausnahme verursacht hat. Neben der Implementierung eines geschützten parameterlosen Konstruktors und eines Konstruktors mit SerializationInfo und StreamingContext Parametern für die Serialisierung definiert die NotPrimeException Klasse drei zusätzliche Konstruktoren zur Unterstützung der NonPrime Eigenschaft. Jeder Konstruktor ruft zusätzlich zum Speichern des Werts der zusammengesetzten Zahl einen Basisklassenkonstruktor auf. Die NotPrimeException Klasse ist auch mit dem SerializableAttribute Attribut gekennzeichnet.
using System;
using System.Runtime.Serialization;
[Serializable()]
public class NotPrimeException : Exception
{
private int notAPrime;
protected NotPrimeException()
: base()
{ }
public NotPrimeException(int value) :
base(String.Format("{0} is not a prime number.", value))
{
notAPrime = value;
}
public NotPrimeException(int value, string message)
: base(message)
{
notAPrime = value;
}
public NotPrimeException(int value, string message, Exception innerException) :
base(message, innerException)
{
notAPrime = value;
}
protected NotPrimeException(SerializationInfo info,
StreamingContext context)
: base(info, context)
{ }
public int NonPrime
{ get { return notAPrime; } }
}
namespace global
open System
open System.Runtime.Serialization
[<Serializable>]
type NotPrimeException =
inherit Exception
val notAPrime: int
member this.NonPrime =
this.notAPrime
new (value) =
{ inherit Exception($"%i{value} is not a prime number."); notAPrime = value }
new (value, message) =
{ inherit Exception(message); notAPrime = value }
new (value, message, innerException: Exception) =
{ inherit Exception(message, innerException); notAPrime = value }
// F# does not support protected members
new () =
{ inherit Exception(); notAPrime = 0 }
new (info: SerializationInfo, context: StreamingContext) =
{ inherit Exception(info, context); notAPrime = 0 }
Imports System.Runtime.Serialization
<Serializable()> _
Public Class NotPrimeException : Inherits Exception
Private notAPrime As Integer
Protected Sub New()
MyBase.New()
End Sub
Public Sub New(value As Integer)
MyBase.New(String.Format("{0} is not a prime number.", value))
notAPrime = value
End Sub
Public Sub New(value As Integer, message As String)
MyBase.New(message)
notAPrime = value
End Sub
Public Sub New(value As Integer, message As String, innerException As Exception)
MyBase.New(message, innerException)
notAPrime = value
End Sub
Protected Sub New(info As SerializationInfo,
context As StreamingContext)
MyBase.New(info, context)
End Sub
Public ReadOnly Property NonPrime As Integer
Get
Return notAPrime
End Get
End Property
End Class
Die PrimeNumberGenerator im folgenden Beispiel gezeigte Klasse verwendet die Sieve von Eratosthenes, um die Sequenz von Primzahlen von 2 auf einen grenzwert zu berechnen, der vom Client im Aufruf des Klassenkonstruktors angegeben wird. Die GetPrimesFrom Methode gibt alle Primzahlen zurück, die größer oder gleich einem angegebenen unteren Grenzwert sind, löst jedoch ein NotPrimeException , wenn diese untere Grenze keine Primzahl ist.
using System;
using System.Collections.Generic;
[Serializable]
public class PrimeNumberGenerator
{
private const int START = 2;
private int maxUpperBound = 10000000;
private int upperBound;
private bool[] primeTable;
private List<int> primes = new List<int>();
public PrimeNumberGenerator(int upperBound)
{
if (upperBound > maxUpperBound)
{
string message = String.Format(
"{0} exceeds the maximum upper bound of {1}.",
upperBound, maxUpperBound);
throw new ArgumentOutOfRangeException(message);
}
this.upperBound = upperBound;
// Create array and mark 0, 1 as not prime (True).
primeTable = new bool[upperBound + 1];
primeTable[0] = true;
primeTable[1] = true;
// Use Sieve of Eratosthenes to determine prime numbers.
for (int ctr = START; ctr <= (int)Math.Ceiling(Math.Sqrt(upperBound));
ctr++)
{
if (primeTable[ctr]) continue;
for (int multiplier = ctr; multiplier <= upperBound / ctr; multiplier++)
if (ctr * multiplier <= upperBound) primeTable[ctr * multiplier] = true;
}
// Populate array with prime number information.
int index = START;
while (index != -1)
{
index = Array.FindIndex(primeTable, index, (flag) => !flag);
if (index >= 1)
{
primes.Add(index);
index++;
}
}
}
public int[] GetAllPrimes()
{
return primes.ToArray();
}
public int[] GetPrimesFrom(int prime)
{
int start = primes.FindIndex((value) => value == prime);
if (start < 0)
throw new NotPrimeException(prime, String.Format("{0} is not a prime number.", prime));
else
return primes.FindAll((value) => value >= prime).ToArray();
}
}
namespace global
open System
[<Serializable>]
type PrimeNumberGenerator(upperBound) =
let start = 2
let maxUpperBound = 10000000
let primes = ResizeArray()
let primeTable =
upperBound + 1
|> Array.zeroCreate<bool>
do
if upperBound > maxUpperBound then
let message = $"{upperBound} exceeds the maximum upper bound of {maxUpperBound}."
raise (ArgumentOutOfRangeException message)
// Create array and mark 0, 1 as not prime (True).
primeTable[0] <- true
primeTable[1] <- true
// Use Sieve of Eratosthenes to determine prime numbers.
for i = start to float upperBound |> sqrt |> ceil |> int do
if not primeTable[i] then
for multiplier = i to upperBound / i do
if i * multiplier <= upperBound then
primeTable[i * multiplier] <- true
// Populate array with prime number information.
let mutable index = start
while index <> -1 do
index <- Array.FindIndex(primeTable, index, fun flag -> not flag)
if index >= 1 then
primes.Add index
index <- index + 1
member _.GetAllPrimes() =
primes.ToArray()
member _.GetPrimesFrom(prime) =
let start =
Seq.findIndex ((=) prime) primes
if start < 0 then
raise (NotPrimeException(prime, $"{prime} is not a prime number.") )
else
Seq.filter ((>=) prime) primes
|> Seq.toArray
Imports System.Collections.Generic
<Serializable()> Public Class PrimeNumberGenerator
Private Const START As Integer = 2
Private maxUpperBound As Integer = 10000000
Private upperBound As Integer
Private primeTable() As Boolean
Private primes As New List(Of Integer)
Public Sub New(upperBound As Integer)
If upperBound > maxUpperBound Then
Dim message As String = String.Format(
"{0} exceeds the maximum upper bound of {1}.",
upperBound, maxUpperBound)
Throw New ArgumentOutOfRangeException(message)
End If
Me.upperBound = upperBound
' Create array and mark 0, 1 as not prime (True).
ReDim primeTable(upperBound)
primeTable(0) = True
primeTable(1) = True
' Use Sieve of Eratosthenes to determine prime numbers.
For ctr As Integer = START To CInt(Math.Ceiling(Math.Sqrt(upperBound)))
If primeTable(ctr) Then Continue For
For multiplier As Integer = ctr To CInt(upperBound \ ctr)
If ctr * multiplier <= upperBound Then primeTable(ctr * multiplier) = True
Next
Next
' Populate array with prime number information.
Dim index As Integer = START
Do While index <> -1
index = Array.FindIndex(primeTable, index, Function(flag)
Return Not flag
End Function)
If index >= 1 Then
primes.Add(index)
index += 1
End If
Loop
End Sub
Public Function GetAllPrimes() As Integer()
Return primes.ToArray()
End Function
Public Function GetPrimesFrom(prime As Integer) As Integer()
Dim start As Integer = primes.FindIndex(Function(value)
Return value = prime
End Function)
If start < 0 Then
Throw New NotPrimeException(prime, String.Format("{0} is not a prime number.", prime))
Else
Return primes.FindAll(Function(value)
Return value >= prime
End Function).ToArray()
End If
End Function
End Class
Im folgenden Beispiel werden zwei Aufrufe der GetPrimesFrom Methode mit Nicht-Primzahlen ausgeführt, von denen eine Anwendungsdomänengrenzen überschreitet. In beiden Fällen wird die Ausnahme ausgelöst und erfolgreich im Clientcode behandelt.
using System;
using System.Reflection;
class Example1
{
public static void Main()
{
int limit = 10000000;
PrimeNumberGenerator primes = new PrimeNumberGenerator(limit);
int start = 1000001;
try
{
int[] values = primes.GetPrimesFrom(start);
Console.WriteLine($"There are {start} prime numbers from {limit} to {2}");
}
catch (NotPrimeException e)
{
Console.WriteLine($"{e.NonPrime} is not prime");
Console.WriteLine(e);
Console.WriteLine("--------");
}
AppDomain domain = AppDomain.CreateDomain("Domain2");
PrimeNumberGenerator gen = (PrimeNumberGenerator)domain.CreateInstanceAndUnwrap(
typeof(Example).Assembly.FullName,
"PrimeNumberGenerator", true,
BindingFlags.Default, null,
new object[] { 1000000 }, null, null);
try
{
start = 100;
Console.WriteLine(gen.GetPrimesFrom(start));
}
catch (NotPrimeException e)
{
Console.WriteLine($"{e.NonPrime} is not prime");
Console.WriteLine(e);
Console.WriteLine("--------");
}
}
}
open System
open System.Reflection
let limit = 10000000
let primes = PrimeNumberGenerator limit
let start = 1000001
try
let values = primes.GetPrimesFrom start
printfn $"There are {values.Length} prime numbers from {start} to {limit}"
with :? NotPrimeException as e ->
printfn $"{e.NonPrime} is not prime"
printfn $"{e}"
printfn "--------"
let domain = AppDomain.CreateDomain "Domain2"
let gen =
domain.CreateInstanceAndUnwrap(
typeof<PrimeNumberGenerator>.Assembly.FullName,
"PrimeNumberGenerator", true,
BindingFlags.Default, null,
[| box 1000000 |], null, null)
:?> PrimeNumberGenerator
try
let start = 100
printfn $"{gen.GetPrimesFrom start}"
with :? NotPrimeException as e ->
printfn $"{e.NonPrime} is not prime"
printfn $"{e}"
printfn "--------"
Imports System.Reflection
Module Example
Sub Main()
Dim limit As Integer = 10000000
Dim primes As New PrimeNumberGenerator(limit)
Dim start As Integer = 1000001
Try
Dim values() As Integer = primes.GetPrimesFrom(start)
Console.WriteLine("There are {0} prime numbers from {1} to {2}",
start, limit)
Catch e As NotPrimeException
Console.WriteLine("{0} is not prime", e.NonPrime)
Console.WriteLine(e)
Console.WriteLine("--------")
End Try
Dim domain As AppDomain = AppDomain.CreateDomain("Domain2")
Dim gen As PrimeNumberGenerator = domain.CreateInstanceAndUnwrap(
GetType(Example).Assembly.FullName,
"PrimeNumberGenerator", True,
BindingFlags.Default, Nothing,
{1000000}, Nothing, Nothing)
Try
start = 100
Console.WriteLine(gen.GetPrimesFrom(start))
Catch e As NotPrimeException
Console.WriteLine("{0} is not prime", e.NonPrime)
Console.WriteLine(e)
Console.WriteLine("--------")
End Try
End Sub
End Module
' The example displays the following output:
' 1000001 is not prime
' NotPrimeException: 1000001 is not a prime number.
' at PrimeNumberGenerator.GetPrimesFrom(Int32 prime)
' at Example.Main()
' --------
' 100 is not prime
' NotPrimeException: 100 is not a prime number.
' at PrimeNumberGenerator.GetPrimesFrom(Int32 prime)
' at Example.Main()
' --------
Beispiele
Im folgenden Beispiel wird ein catch-Block (in F# als with) veranschaulicht, der zum Behandeln von ArithmeticException-Fehlern definiert ist. Dieser catch Block erfasst auch DivideByZeroException Fehler, weil DivideByZeroException von ArithmeticException abgeleitet ist und kein catch Block explizit für DivideByZeroException Fehler definiert ist.
using System;
class ExceptionTestClass
{
public static void Main()
{
int x = 0;
try
{
int y = 100 / x;
}
catch (ArithmeticException e)
{
Console.WriteLine($"ArithmeticException Handler: {e}");
}
catch (Exception e)
{
Console.WriteLine($"Generic Exception Handler: {e}");
}
}
}
/*
This code example produces the following results:
ArithmeticException Handler: System.DivideByZeroException: Attempted to divide by zero.
at ExceptionTestClass.Main()
*/
module ExceptionTestModule
open System
let x = 0
try
let y = 100 / x
()
with
| :? ArithmeticException as e ->
printfn $"ArithmeticException Handler: {e}"
| e ->
printfn $"Generic Exception Handler: {e}"
// This code example produces the following results:
// ArithmeticException Handler: System.DivideByZeroException: Attempted to divide by zero.
// at <StartupCode$fs>.$ExceptionTestModule.main@()
Class ExceptionTestClass
Public Shared Sub Main()
Dim x As Integer = 0
Try
Dim y As Integer = 100 / x
Catch e As ArithmeticException
Console.WriteLine("ArithmeticException Handler: {0}", e.ToString())
Catch e As Exception
Console.WriteLine("Generic Exception Handler: {0}", e.ToString())
End Try
End Sub
End Class
'
'This code example produces the following results:
'
'ArithmeticException Handler: System.OverflowException: Arithmetic operation resulted in an overflow.
' at ExceptionTestClass.Main()
'