System.Exception-Klasse

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 diesen, 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 Standardausnahmehandler behandelt.

Fehler und Ausnahmen

Laufzeitfehler können aus verschiedenen Gründen auftreten. Nicht alle Fehler sollten jedoch als Ausnahmen in Ihrem Code behandelt werden. Nachfolgend finden Sie einige Fehlerkategorien, 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 die Korrektur des fehlerhaften Codes. Die Außerkraftsetzung der Object.Equals(Object)-Methode im folgenden Beispiel geht beispielsweise davon aus, dass das Argument obj nie NULL sein darf.

    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: {0}", 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 Module
    

    Die NullReferenceException-Ausnahme, die entsteht, wenn obj gleich null ist, 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 ein null-Argument verarbeitet.

    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: {0}", 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: False
    
    Public 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: False
    

    Anstatt die Ausnahmebehandlung für Verwendungsfehler zu verwenden, können Sie die Debug.Assert-Methode verwenden, um Verwendungsfehler in Debugbuilds zu ermitteln, und die Trace.Assert-Methode, um Verwendungsfehler in Debug- und Releasebuilds zu ermitteln. Weitere Informationen finden Sie unter Assertionen in verwaltetem Code.

  • Programmfehler: Ein Programmfehler ist ein Laufzeitfehler, der nicht immer durch Schreiben von fehlerfreiem Code vermieden werden kann.

    In einigen Fällen kann ein Programmfehler eine erwartete oder routinemäßige Fehlerbedingung darstellen. In diesem Fall sollten Sie die Verwendung der Ausnahmebehandlung vermeiden, um den Programmfehler zu behandeln, und den Vorgang stattdessen wiederholen. Wenn beispielsweise erwartet wird, dass der oder die Benutzer*in ein Datum in einem bestimmten Format eingibt, können Sie die Datumszeichenfolge parsen, indem Sie die DateTime.TryParseExact-Methode aufrufen, die einen Boolean-Wert zurückgibt. Dieser gibt an, ob der Parsingvorgang erfolgreich war, anstatt die DateTime.ParseExact-Methode zu verwenden, wodurch eine FormatException-Ausnahme ausgelöst wird, wenn die Datumszeichenfolge nicht in einen DateTime-Wert konvertiert werden kann. Wenn ein*e Benutzer*in 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 das nicht der Fall ist, wird der oder die Benutzer*in gefragt, ob die Datei erstellt werden soll.

    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, könnte sie gelöscht worden sein, bevor Sie sie öffnen konnten, oder sie ist beschädigt. In diesem Fall wird beim Versuch, die Datei zu öffnen, indem ein StreamReader-Objekt instanziiert oder die Open-Methode aufgerufen wird, möglicherweise eine FileNotFoundException-Ausnahme ausgelöst. In diesen Fällen sollten Sie die Ausnahmebehandlung verwenden, um den Fehler zu korrigieren.

  • Systemfehler: Ein Systemfehler ist ein Laufzeitfehler, der programmgesteuert nicht effizient behandelt werden kann. Beispielsweise kann jede Methode eine OutOfMemoryException-Ausnahme auslösen, wenn die Common Language Runtime keinen zusätzlichen Arbeitsspeicher belegen 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 oder die Benutzerin ü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 und der Trennung von Programmcode und Ausnahmebehandlungscode in try-Blöcke und catch-Blöcke basiert. Es kann einen oder mehrere catch-Blöcke geben, die jeweils für die Behandlung eines bestimmten Ausnahmetyps vorgesehen sind, oder einen Block, der eine spezifischere Ausnahme als ein anderer Block abfangen soll.

Wenn eine Anwendung Ausnahmen behandelt, die während der Ausführung eines Anwendungscodeblocks auftreten, muss der Code in einer try-Anweisung platziert werden. Dieser Code wird als try-Block bezeichnet. Anwendungscode, der Ausnahmen behandelt, die von einem try-Block ausgelöst werden, wird in einer catch-Anweisung platziert und als catch-Block bezeichnet. Null oder mehr catch-Blöcke werden einem try-Block zugeordnet, und jeder catch-Block enthält einen Typfilter, der die von ihm behandelten Ausnahmen bestimmt.

Wenn eine Ausnahme in einem try-Block auftritt, durchsucht das System die zugeordneten catch-Blöcke in der Reihenfolge, in der sie im Anwendungscode vorkommen, 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 beliebigen 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 verarbeitet, vor einem catch-Block angegeben werden, der seine Basistypen verarbeitet. Dies wird im folgenden Beispiel veranschaulicht. Ein catch-Block, der System.Exception behandelt, wird zuletzt angegeben.

Wenn keine der catch-Blöcke, die dem aktuellen try-Block zugeordnet sind, die Ausnahme behandeln, und der aktuelle try-Block in anderen try-Blöcken im aktuellen Aufruf geschachtelt ist, werden die catch-Blöcke durchsucht, die dem nächsten eingeschlossenen try-Block zugeordnet sind. 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, wird die Ausnahme an die Aufrufliste übergeben, und der vorherige Stapelrahmen wird nach einem catch-Block durchsucht, der die Ausnahme behandelt. Das Durchsuchen der Aufrufliste wird fortgesetzt, bis die Ausnahme behandelt wird oder keine weiteren Frames in der Aufrufliste vorhanden sind. Wenn das obere Ende der Aufrufliste erreicht ist und kein catch-Block gefunden wurde, der die Ausnahme behandelt, behandelt der Standardausnahmehandler 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 statt um eine Anweisung handelt, müssen alle Pfade denselben Typ zurückgeben. Weitere Informationen finden Sie unter try...with-Ausdruck.

Features für Ausnahmetypen

Ausnahmetypen unterstützen die folgenden Features:

  • Lesbarer Text, der den Fehler beschreibt: Wenn eine Ausnahme auftritt, stellt die Runtime eine Textnachricht zur Verfügung, um den oder die Benutzer*in ü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 Ausnahme zu beschreiben. Wenn dem Konstruktor kein Fehlermeldungsargument übergeben 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 Stapelüberwachung, mit der bestimmt werden kann, wo der Fehler im Code auftritt. Die Stapelüberwachung listet alle aufgerufenen Methoden und die Zeilennummern in der Quelldatei auf, in der die Aufrufe getätigt werden.

Eigenschaften von Ausnahmeklassen

Die Exception-Klasse enthält eine Reihe von Eigenschaften, mit denen der Codespeicherort, der Typ, die Hilfedatei und der Grund für die Ausnahme ermittelt werden können: 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 Collection von Schlüssel-Wert-Paaren in der Eigenschaft Data 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 Artikeln Erstellen von Satellitenassemblys und Packen und Bereitstellen von Ressourcen.

Um Benutzer*innen umfangreiche Informationen darüber zu liefern, warum die Ausnahme aufgetreten ist, kann die HelpLink-Eigenschaft eine URL (oder URN) zu einer Hilfedatei enthalten.

Die Exception-Klasse verwendet HRESULT COR_E_EXCEPTION mit dem Wert 0x80131500.

Eine Liste der anfänglichen Eigenschaftenwerte für eine Instanz der Exception-Klasse finden Sie in den Exception-Konstruktoren.

Überlegungen zur Leistung

Das Auslösen oder Behandeln einer Ausnahme verbraucht eine erhebliche Menge an Systemressourcen und benötigt eine lange Ausführungszeit. Lösen Sie Ausnahmen nur aus, um wirklich außergewöhnliche Bedingungen zu behandeln, nicht für vorhersehbare Ereignisse oder die Ablaufsteuerung. In einigen Fällen, z. B. beim Entwickeln einer Klassenbibliothek, ist es sinnvoll, eine Ausnahme auszulösen, 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 zu erwarten ist, dass Benutzer*innen gelegentlich ungültige Daten eingeben. Implementieren Sie stattdessen einen Wiederholungsmechanismus, damit Benutzer*innen gültige Eingaben machen können. Sie sollten auch keine Ausnahmen verwenden, um Verwendungsfehler zu behandeln. Verwenden Sie stattdessen Assertionen, um Verwendungsfehler zu ermitteln und zu beheben.

Lösen Sie außerdem keine Ausnahme aus, wenn ein Rückgabecode ausreichend ist. Konvertieren Sie keinen Rückgabecode in eine Ausnahme, und fangen Sie Ausnahmen nicht routinemäßig ab, ignorieren sie und fahren dann mit der Verarbeitung fort.

Erneutes Auslösen einer Ausnahme

In vielen Fällen soll ein Ausnahmehandler die Ausnahme nur an den Aufrufer übergeben. Das ist am häufigsten der Fall bei:

  • 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, eine Ausnahme erneut auszulösen, besteht darin, die throw-Anweisung in C# zu verwenden, die reraise-Funktion in F# oder die Throw-Anweisung ohne Ausdruck in Visual Basic. Dadurch wird sichergestellt, dass alle Aufruflisteninformationen beibehalten werden, wenn die Ausnahme an den Aufrufer weitergegeben wird. Dies wird anhand des folgenden Beispiels veranschaulicht. Eine Zeichenfolgenerweiterungsmethode, FindOccurrences, umschließt einen oder mehrere Aufrufe von String.IndexOf(String, Int32), ohne die Argumente vorher zu überprüfen.

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 Aufrufer ruft dann zweimal FindOccurrences auf. Im zweiten Aufruf von FindOccurrencesübergibt der Aufrufer 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 aus dem Beispiel, dass die Aufrufliste beibehalten wird.

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 ({0}) occurred.",
                              e.GetType().Name);
            Console.WriteLine("Message:\n   {0}\n", e.Message);
            Console.WriteLine("Stack Trace:\n   {0}\n", e.StackTrace);
        }
    }

    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 die vollständige Aufrufliste 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 Aufrufer kann dann die InnerException-Eigenschaft der neuen Ausnahme verwenden, um Stapelrahmen und andere Informationen zur 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 ({0}) occurred.",
                      e.GetType().Name);
    Console.WriteLine("   Message:\n{0}", e.Message);
    Console.WriteLine("   Stack Trace:\n   {0}", e.StackTrace);
    Exception ie = e.InnerException;
    if (ie != null)
    {
        Console.WriteLine("   The Inner Exception:");
        Console.WriteLine("      Exception Name: {0}", ie.GetType().Name);
        Console.WriteLine("      Message: {0}\n", ie.Message);
        Console.WriteLine("      Stack Trace:\n   {0}\n", ie.StackTrace);
    }
}
// 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 Standardausnahmen

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 Standardausnahmetyp verwenden:

  • Sie lösen eine Ausnahme aus, die durch einen Verwendungsfehler verursacht wird (d. h. durch einen Fehler in der Programmlogik des Entwicklers oder der Entwicklerin, der oder die Ihre Methode aufruft). In der Regel würden Sie eine Ausnahme wie ArgumentException, ArgumentNullException, InvalidOperationException oder NotSupportedException auslösen. Die Zeichenfolge, die Sie beim Instanziieren des Ausnahmeobjekts für den Konstruktor des Ausnahmeobjekts angeben, sollte den Fehler beschreiben, damit der oder die Entwickler*in 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 z. B. ein Argument als gültiges Element eines Enumerationstyps erfordert, sollten Sie InvalidEnumArgumentException (die am häufigsten abgeleitete Klasse) anstelle von ArgumentException auslösen.

In der folgenden Tabelle sind allgemeine Ausnahmetypen und die Bedingungen aufgeführt, unter denen Sie sie auslösen würden.

Exception Bedingung
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 einem Divisionsvorgang mit Integer- oder Decimal-Werten ist null.
DriveNotFoundException Ein Laufwerk ist nicht verfügbar oder nicht vorhanden.
FileNotFoundException Eine Datei ist nicht vorhanden.
FormatException Ein Wert weist kein geeignetes Format auf, um durch eine Konvertierungsmethode wie Parse aus einer Zeichenfolge konvertiert zu werden.
IndexOutOfRangeException Ein Index liegt außerhalb der Grenzen eines Arrays oder einer Collection.
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 Collection 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 keiner vorhandenen .NET-Ausnahme 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 von einer ähnlichen Ausnahme getrennt werden muss. Wenn Sie beispielsweise beim Analysieren der numerischen Darstellung einer Zeichenfolge, die außerhalb des Bereichs des Zielintegraltyps liegt, eine ArgumentOutOfRangeException-Ausnahme auslösen, sollten Sie beim Aufrufen der Methode nicht dieselbe Ausnahme für einen Fehler verwenden, der aus dem Aufrufer resultiert, ohne die entsprechenden eingeschränkten Werte anzugeben.

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 Exception noch definieren sie eindeutige Member.

So definieren Sie Ihre eigene Ausnahmeklasse:

  1. 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 ArgumentException-Klasse enthält beispielsweise eine ParamName-Eigenschaft, die den Namen des Parameters angibt, dessen Argument die Ausnahme verursacht hat, und die RegexMatchTimeoutException-Eigenschaft enthält eine MatchTimeout-Eigenschaft, die das Timeoutintervall angibt.

  2. Setzen Sie bei Bedarf alle geerbten Member außer Kraft, deren Funktionalität Sie ändern möchten. Beachten Sie, dass die meisten vorhandenen abgeleiteten Klassen von Exception das Verhalten von geerbten Membern nicht außer Kraft setzen.

  3. 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 Attribut SerializableAttribute.

  4. Definieren Sie die Konstruktoren Ihrer Ausnahmeklasse. In der Regel verfügen Ausnahmeklassen über einen oder mehrere der folgenden Konstruktoren:

    • Exception(), der Standardwerte verwendet, um die Eigenschaften eines neuen Ausnahmeobjekts zu initialisieren

    • Exception(String), der ein neues Ausnahmeobjekt mit einer angegebenen Fehlermeldung initialisiert

    • Exception(String, Exception), der ein neues Ausnahmeobjekt mit einer angegebenen Fehlermeldung und einer inneren Ausnahme initialisiert

    • Exception(SerializationInfo, StreamingContext), bei dem es sich um einen protected-Konstruktor handelt, der ein neues Ausnahmeobjekt aus serialisierten Daten initialisiert. Sie sollten diesen Konstruktor implementieren, wenn Sie beschlossen haben, das Ausnahmeobjekt serialisierbar zu machen.

Das folgende Beispiel veranschaulicht die Verwendung einer benutzerdefinierten Ausnahmeklasse. Es definiert eine NotPrimeException-Ausnahme, die ausgelöst wird, wenn ein Client versucht, eine Sequenz von Primzahlen abzurufen, indem eine Anfangsnummer angegeben wird, die keine Primzahl ist. Die Ausnahme definiert eine neue Eigenschaft, NonPrime, die die zusammengesetzte Zahl 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 Attribut SerializableAttribute 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 im folgenden Beispiel gezeigte PrimeNumberGenerator-Klasse verwendet das Sieb des Eratosthenes, um die Primzahlsequenz von 2 bis zu einem 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 einer angegebenen Untergrenze sind, löst jedoch NotPrimeException aus, wenn dieser untere Grenzwert 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 zusammengesetzten Zahlen ausgeführt, von denen eine die 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 {0} prime numbers from {1} to {2}",
                              start, limit);
        }
        catch (NotPrimeException e)
        {
            Console.WriteLine("{0} is not prime", e.NonPrime);
            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("{0} is not prime", e.NonPrime);
            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 (with in F#) veranschaulicht, der für die Behandlung von ArithmeticException-Fehlern definiert ist. Dieser catch-Block erfasst auch DivideByZeroException-Fehler, da 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()
'