Untersuchen, wie Ausnahmen in C erstellt und ausgelöst werden#
- 16 Minuten
.NET stellt eine Hierarchie von Ausnahmeklassen bereit, die von der System.Exception Basisklasse abgeleitet sind. C#-Anwendungen können Ausnahmen eines beliebigen Ausnahmetyps erstellen und auslösen. Entwickler können Ausnahmeobjekte auch mit anwendungsspezifischen Informationen anpassen, indem Eigenschaftenwerte zugewiesen werden.
Hinweis
Dieses Modul konzentriert sich auf das Erstellen und Auslösen von Ausnahmen und das Anpassen von Ausnahmeobjekten. Das Erstellen benutzerdefinierter Ausnahmeklassen liegt außerhalb des Bereichs dieses Moduls.
Erstellen eines Ausnahmeobjekts
Das Erstellen und Auslösen von Ausnahmen aus Ihrem Code ist ein wichtiger Aspekt der C#-Programmierung. Die Möglichkeit, eine Ausnahme als Reaktion auf eine bestimmte Bedingung, ein Problem oder einen Fehler zu generieren, hilft Ihnen, die Stabilität Ihrer Anwendung sicherzustellen.
Der von Ihnen erstellte Ausnahmetyp hängt vom Codierungsproblem ab und sollte dem beabsichtigten Zweck der Ausnahme so genau wie möglich entsprechen.
Angenommen, Sie erstellen eine Methode namens GraphData, die Datenanalysen durchführt. Die Methode empfängt ein Datenarray als Eingabeparameter. Die Methode erwartet, dass sich die Eingabedaten in einem bestimmten Bereich befinden. Wenn die Methode Daten empfängt, die sich außerhalb des erwarteten Bereichs befinden, wird eine Ausnahme vom Typ ArgumentExceptionerstellt und ausgelöst. Die Ausnahmebehandlung erfolgt dann weiter unten in der Aufrufliste durch den Code, der für die Bereitstellung der Daten verantwortlich ist.
Im Folgenden finden Sie einige gängige Ausnahmetypen, die Sie beim Erstellen einer Ausnahme verwenden können:
-
ArgumentExceptionoderArgumentNullException: Verwenden Sie diese Ausnahmetypen, wenn eine Methode oder ein Konstruktor mit einem ungültigen Argumentwert oder null-Verweis aufgerufen wird. -
InvalidOperationException: Verwenden Sie diesen Ausnahmetyp, wenn die Betriebsbedingungen einer Methode den erfolgreichen Abschluss eines bestimmten Methodenaufrufs nicht unterstützen. -
NotSupportedException: Verwenden Sie diesen Ausnahmetyp, wenn ein Vorgang oder ein Feature nicht unterstützt wird. -
IOException: Verwenden Sie diesen Ausnahmetyp, wenn ein Eingabe-/Ausgabevorgang fehlschlägt. -
FormatException: Verwenden Sie diesen Ausnahmetyp, wenn das Format einer Zeichenfolge oder Daten falsch ist.
Das new Schlüsselwort wird verwendet, um eine Instanz einer Ausnahme zu erstellen. Sie können beispielsweise eine Instanz des ArgumentException Ausnahmetyps wie folgt erstellen:
ArgumentException invalidArgumentException = new ArgumentException();
Konfigurieren und Auslösen von benutzerdefinierten Ausnahmen
Der Prozess zum Auslösen eines Ausnahmeobjekts umfasst das Erstellen einer Instanz einer vom Ausnahme abgeleiteten Klasse, optional das Konfigurieren von Eigenschaften der Ausnahme und das Anschließende Auslösen des Objekts mithilfe des throw Schlüsselworts.
Es ist häufig hilfreich, eine Ausnahme mit kontextbezogenen Informationen anzupassen, bevor sie ausgelöst wird. Sie können anwendungsspezifische Informationen innerhalb eines Ausnahmeobjekts bereitstellen, indem Sie dessen Eigenschaften konfigurieren. Der folgende Code erstellt z. B. ein Ausnahmeobjekt invalidArgumentException mit einer benutzerdefinierten Message Eigenschaft und löst dann die Ausnahme aus:
ArgumentException invalidArgumentException = new ArgumentException("ArgumentException: The 'GraphData' method received data outside the expected range.");
throw invalidArgumentException;
Hinweis
Die Eigenschaft Message einer Ausnahme ist schreibgeschützt. Daher muss beim Instanziieren des Objekts eine benutzerdefinierte Message Eigenschaft festgelegt werden.
Beim Anpassen eines Ausnahmeobjekts ist es wichtig, klare Fehlermeldungen bereitzustellen, die das Problem beschreiben und wie sie behoben werden können. Sie können auch zusätzliche Informationen wie Stapelablaufverfolgungen und Fehlercodes einfügen, um Benutzern bei der Behebung des Problems zu helfen.
Ein Ausnahmeobjekt kann auch direkt in einer throw Anweisung erstellt werden. Beispiel:
throw new FormatException("FormatException: Calculations in process XYZ have been cancelled due to invalid data format.");
Einige Überlegungen, die Sie beim Auslösen einer Ausnahme berücksichtigen sollten, sind:
- Die
MessageEigenschaft sollte den Grund für die Ausnahme erläutern. Informationen, die vertraulich sind oder ein Sicherheitsproblem darstellen, sollten jedoch nicht in den Nachrichtentext gesetzt werden. - Die
StackTraceEigenschaft wird häufig verwendet, um den Ursprung der Ausnahme nachzuverfolgen. Diese Zeichenfolgeneigenschaft enthält den Namen der Methoden im aktuellen Aufrufstapel zusammen mit dem Dateinamen und der Zeilennummer in jeder Methode, die der Ausnahme zugeordnet ist. Die Common Language Runtime (CLR) erstellt automatisch einStackTrace-Objekt ab der Position derthrow-Anweisung. Ausnahmen müssen ab dem Punkt ausgelöst werden, an dem die Stapelüberwachung beginnen soll.
Wann sollte eine Ausnahme ausgelöst werden
Methoden sollten eine Ausnahme auslösen, wenn sie ihren beabsichtigten Zweck nicht abschließen können. Die ausgelöste Ausnahme sollte auf der spezifischen Ausnahme basieren, die den Fehlerbedingungen entspricht.
Betrachten Sie ein Szenario, in dem ein Entwickler an einer Anwendung arbeitet, die einen Geschäftsprozess implementiert. Der Geschäftsprozess hängt von der Benutzereingabe ab. Wenn die Eingabe nicht mit dem erwarteten Datentyp übereinstimmt, erstellt und löst die Methode, die den Geschäftsprozess implementiert, eine Ausnahme aus. Das Ausnahmeobjekt kann mit anwendungsspezifischen Informationen in den Eigenschaftswerten konfiguriert werden. Das folgende Codebeispiel veranschaulicht das Szenario:
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach (string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1") && (ex is FormatException))
{
Console.WriteLine(ex.Message);
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
// completes required calculations based on userValue
// ...
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
}
}
In diesem Codebeispiel rufen die Anweisungen der obersten Ebene die BusinessProcess1 Methode auf und übergeben ein Zeichenfolgenarray, das vom Benutzer eingegebene Werte enthält. Die BusinessProcess1 Methode erwartet Benutzereingabewerte, die in eine ganze Zahl konvertiert werden können. Wenn die Methode auf Daten mit einem ungültigen Format trifft, wird eine Instanz des FormatException Ausnahmetyps mithilfe einer angepassten Message Eigenschaft erstellt. Anschließend löst die Methode die Ausnahme aus. Die Ausnahme wird in den Anweisungen der obersten Ebene als ein Objekt mit dem Namen ex abgefangen. Eigenschaften des ex Objekts werden untersucht, bevor dem Benutzer die Ausnahmemeldung angezeigt wird. Zunächst überprüft der Code die StackTrace Eigenschaft, um festzustellen, ob sie "BusinessProcess1" enthält. Zweitens wird das Ausnahmeobjekt ex überprüft, um vom Typ FormatExceptionzu sein.
Erneutes Auslösen von Ausnahmen
Zusätzlich zur Auslösung einer neuen Ausnahme kann throw verwendet werden, um eine Ausnahme innerhalb eines catch Codeblocks erneut zu werfen. In diesem Fall akzeptiert throw keinen Ausnahmeoperand.
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// re-throw the original exception object for further handling down the call stack
throw;
}
Wenn Sie eine Ausnahme erneut auslösen, wird das ursprüngliche Ausnahmeobjekt verwendet, sodass keine Informationen zur Ausnahme verloren gehen. Wenn Sie ein neues Ausnahmeobjekt erstellen möchten, das die ursprüngliche Ausnahme umschließt, können Sie die ursprüngliche Ausnahme als Argument an den Konstruktor eines neuen Ausnahmeobjekts übergeben. Beispiel:
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred", ex);
}
Berücksichtigen Sie für das Anwendungsszenario "BusinessProcess1" die folgenden Updates:
- Die
BusinessProcess1Methode wurde aktualisiert, um zusätzliche Details einzuschließen.BusinessProcess1stößt nun auf zwei Probleme und muss für jedes Problem eine Ausnahme generieren. - Die Anweisungen der obersten Ebene wurden aktualisiert. Anweisungen der obersten Ebene rufen jetzt die
OperatingProcedure1Methode auf.OperatingProcedure1ruftBusinessProcess1innerhalb einestryCode-Blocks auf. - Die
OperatingProcedure1Methode kann einen der Ausnahmetypen behandeln und die andere teilweise behandeln. Sobald die teilweise behandelte Ausnahme verarbeitet wurde, mussOperatingProcedure1die ursprüngliche Ausnahme erneut auslösen.
Das folgende Codebeispiel veranschaulicht das aktualisierte Szenario:
try
{
OperatingProcedure1();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Exiting application.");
}
static void OperatingProcedure1()
{
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach(string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1"))
{
if (ex is FormatException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Corrective action taken in OperatingProcedure1");
}
else if (ex is DivideByZeroException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Partial correction in OperatingProcedure1 - further action required");
// re-throw the original exception
throw;
}
else
{
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred - ", ex);
}
}
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
checked
{
int calculatedValue = 4 / valueEntered;
}
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
catch (DivideByZeroException)
{
DivideByZeroException unexpectedDivideByZeroException = new DivideByZeroException("DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero");
throw unexpectedDivideByZeroException;
}
}
}
Der aktualisierte Beispielcode erzeugt die folgende Ausgabe:
FormatException: User input values in 'BusinessProcess1' must be valid integers
Corrective action taken in OperatingProcedure1
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Partial correction in OperatingProcedure1 - further action required
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Exiting application.
Dinge, die beim Auslösen von Ausnahmen vermieden werden müssen
In der folgenden Liste werden Methoden aufgeführt, die beim Auslösen von Ausnahmen vermieden werden sollen:
- Verwenden Sie keine Ausnahmen, um den Fluss eines Programms als Teil der normalen Ausführung zu ändern. Verwenden Sie Ausnahmen zum Melden und Behandeln von Fehlerbedingungen.
- Ausnahmen sollten nicht als Rückgabewert oder Parameter zurückgegeben werden, sie sollten ausgelöst werden.
- Lösen Sie nicht
System.Exception,System.SystemException,System.NullReferenceExceptionoderSystem.IndexOutOfRangeExceptionabsichtlich aus Ihrem eigenen Quellcode aus. - Erstellen Sie keine Ausnahmen, die im Debugmodus ausgelöst werden können, jedoch nicht im Freigabemodus. Verwenden Sie stattdessen die Verwendung
Debug.Assert, um Laufzeitfehler während der Entwicklungsphase zu identifizieren.
Hinweis
Die Debug.Assert Methode ist ein Tool zum Abfangen von Logikfehlern während der Entwicklung. Standardmäßig funktioniert die Debug.Assert Methode nur in Debugbuilds. Sie können Debug.Assert in Debugsitzungen verwenden, um nach einer Bedingung zu suchen, die niemals auftreten sollte. Die Methode verwendet zwei Parameter: eine boolesche Bedingung, die überprüft werden soll, und eine optionale Zeichenfolgenmeldung, die angezeigt werden soll, wenn die Bedingung lautet false.
Debug.Assert ermöglicht das Behandeln von Ausnahmesituationen während der normalen Ausführung Ihres Codes und sollte nicht anstelle der Auslösung einer Ausnahme verwendet werden. Verwenden Sie diese Methode Debug.Assert , um Fehler zu erfassen, die niemals auftreten sollten, und Ausnahmen zum Behandeln von Fehlern verwenden, die während der normalen Ausführung des Programms auftreten können.
Rekapitulation
Nachstehend finden Sie nochmals die wichtigsten Punkte aus dieser Lerneinheit:
- Beim Erstellen und Auslösen einer Ausnahme muss der Ausnahmetyp dem beabsichtigten Zweck der Ausnahme so genau wie möglich entsprechen.
- Um
throweine Ausnahme zu generieren, erstellen Sie eine Instanz einer abgeleiteten Ausnahme-Klasse, konfigurieren deren Eigenschaften und verwenden dann dasthrowSchlüsselwort. - Beim Erstellen eines Ausnahmeobjekts ist es wichtig, klare Fehlermeldungen und zusätzliche Informationen bereitzustellen, damit Benutzer das Problem beheben können.
Überprüfen Sie Ihr Wissen
Feedback
War diese Seite hilfreich?
No
Benötigen Sie Hilfe zu diesem Thema?
Möchten Sie versuchen, Ask Learn zu verwenden, um Sie durch dieses Thema zu klären oder zu leiten?