Ich bin auf diese neue Funktion in C # gestoßen, mit der ein Catch-Handler ausgeführt werden kann, wenn eine bestimmte Bedingung erfüllt ist.
int i = 0;
try
{
throw new ArgumentNullException(nameof(i));
}
catch (ArgumentNullException e)
when (i == 1)
{
Console.WriteLine("Caught Argument Null Exception");
}
Ich versuche zu verstehen, wann dies jemals nützlich sein kann.
Ein Szenario könnte ungefähr so aussehen:
try
{
DatabaseUpdate()
}
catch (SQLException e)
when (driver == "MySQL")
{
//MySQL specific error handling and wrapping up the exception
}
catch (SQLException e)
when (driver == "Oracle")
{
//Oracle specific error handling and wrapping up of exception
}
..
Aber dies ist wieder etwas, das ich innerhalb desselben Handlers tun und je nach Treibertyp an verschiedene Methoden delegieren kann. Ist der Code dadurch leichter zu verstehen? Wohl nein.
Ein anderes Szenario, an das ich denken kann, ist so etwas wie:
try
{
SomeOperation();
}
catch(SomeException e)
when (Condition == true)
{
//some specific error handling that this layer can handle
}
catch (Exception e) //catchall
{
throw;
}
Auch dies ist etwas, was ich tun kann:
try
{
SomeOperation();
}
catch(SomeException e)
{
if (condition == true)
{
//some specific error handling that this layer can handle
}
else
throw;
}
Verbessert die Verwendung der Funktion "catch, when" die Ausnahmebehandlung, da der Handler als solcher übersprungen wird und das Abwickeln des Stapels viel früher erfolgen kann als bei der Behandlung der spezifischen Anwendungsfälle innerhalb des Handlers? Gibt es spezielle Anwendungsfälle, die besser zu dieser Funktion passen und die dann als bewährte Methode übernommen werden können?
quelle
when
Ausnahme selbst zugreifen musstry..catch...catch..catch..finally
?catch (Exception ex)
, den Typ prüfen undthrow
sonst. Etwas besser organisierter Code (auch bekannt als Vermeiden von Code-Rauschen) ist genau der Grund, warum diese Funktion vorhanden ist. (Dies gilt tatsächlich für viele Funktionen.)Antworten:
Mit Catch-Blöcken können Sie bereits nach dem Typ der Ausnahme filtern :
Mit dieser
when
Klausel können Sie diesen Filter auf generische Ausdrücke erweitern.Daher verwenden Sie die
when
Klausel für Fälle, in denen der Typ der Ausnahme nicht eindeutig genug ist, um zu bestimmen, ob die Ausnahme hier behandelt werden soll oder nicht.Ein häufiger Anwendungsfall sind Ausnahmetypen, die tatsächlich ein Wrapper für mehrere verschiedene Arten von Fehlern sind.
Hier ist ein Fall, den ich tatsächlich verwendet habe (in VB, das diese Funktion bereits seit einiger Zeit bietet):
Gleiches gilt für
SqlException
, das auch eineErrorCode
Eigenschaft hat. Die Alternative wäre so etwas:Das ist wohl weniger elegant und bricht leicht die Stapelspur .
Darüber hinaus können Sie das gleiche erwähnen Art ausnahmsweise zweimal im selben Try-Catch-Block:
was ohne die
when
Bedingung nicht möglich wäre .quelle
catch
, oder?when
Option können Sie denselben Ausnahmetyp mehrmals behandeln. Sie sollten das auch erwähnen, da es ein entscheidender Unterschied ist. Ohne erhaltenwhen
Sie einen Compilerfehler.Aus Roslyns Wiki (Schwerpunkt Mine):
Der erste Punkt ist es wert, demonstriert zu werden.
Wenn wir dies in WinDbg ausführen, bis die Ausnahme getroffen wird, und den Stapel mit drucken, sehen
!clrstack -i -a
wir nur den Rahmen vonA
:Wenn wir jedoch das zu verwendende Programm ändern
when
:Wir werden sehen, dass der Stapel auch den Rahmen enthält
B
:Diese Informationen können beim Debuggen von Crash-Dumps sehr nützlich sein.
quelle
throw;
(im Gegensatz zuthrow ex;
) verlassen den unversehrt Stapel als auch? +1 für die Nebeneffektsache. Ich bin mir nicht sicher, ob ich damit einverstanden bin, aber es ist gut, über diese Technik Bescheid zu wissen.throw;
, wird der Stapel abgewickelt und Sie verlieren die Parameterwerte.throw;
sich die Stapelverfolgung ein wenigthrow ex;
ändert und sich stark ändert.throw
stört die Stapelverfolgung geringfügig. Zeilennummern unterscheiden sich bei der Verwendungthrow
im Gegensatz zuwhen
.Wenn eine Ausnahme ausgelöst wird, gibt der erste Durchgang der Ausnahmebehandlung an, wo die Ausnahme zuvor abgefangen wird der Stapel abgewickelt wird. Wenn der Ort "catch" identifiziert wird, werden alle "finally" -Blöcke ausgeführt (beachten Sie, dass die Verarbeitung der früheren Ausnahme möglicherweise abgebrochen wird, wenn eine Ausnahme einem "finally" -Block entgeht. Sobald dies geschieht, setzt der Code die Ausführung am "catch" fort.
Wenn es innerhalb einer Funktion einen Haltepunkt gibt, der als Teil eines "Wann" ausgewertet wird, setzt dieser Haltepunkt die Ausführung aus, bevor ein Abwickeln des Stapels erfolgt. Im Gegensatz dazu wird ein Haltepunkt an einem "catch" die Ausführung schließlich nur aussetzen
finally
Handler ausgeführt wurden.Wenn schließlich die Zeilen 23 und 27 des
foo
Aufrufsbar
und der Anruf in Zeile 23 eine Ausnahmefoo
auslösen, die in Zeile 57 abgefangen und erneut ausgelöst wird, deutet die Stapelverfolgung darauf hin, dass die Ausnahme beim Aufrufenbar
von Zeile 57 [Ort des erneuten Auslösens] aufgetreten ist. und alle Informationen darüber zu zerstören, ob die Ausnahme beim Anruf in Leitung 23 oder 27 aufgetreten ist. Durch die Verwendungwhen
, um zu vermeiden, dass eine Ausnahme abgefangen wird, werden solche Störungen vermieden.Übrigens ist ein nützliches Muster, das sowohl in C # als auch in VB.NET ärgerlich umständlich ist, die Verwendung eines Funktionsaufrufs innerhalb einer
when
Klausel, um eine Variable festzulegen, die innerhalb einerfinally
Klausel verwendet werden kann, um zu bestimmen, ob die Funktion normal ausgeführt wurde, um Fälle zu behandeln, in denen eine Funktion vorliegt hat keine Hoffnung, eine auftretende Ausnahme zu "lösen", muss aber dennoch darauf basierende Maßnahmen ergreifen. Wenn beispielsweise eine Ausnahme innerhalb einer Factory-Methode ausgelöst wird, die ein Objekt zurückgeben soll, das Ressourcen kapselt, müssen alle erworbenen Ressourcen freigegeben werden. Die zugrunde liegende Ausnahme sollte jedoch bis zum Aufrufer versickern. Der sauberste Weg, dies semantisch (wenn auch nicht syntaktisch) zu handhaben, ist afinally
Blockprüfung, ob eine Ausnahme aufgetreten ist, und in diesem Fall alle Ressourcen freizugeben, die für das Objekt erworben wurden, das nicht mehr benötigt wird zurück. Da der Bereinigungscode keine Hoffnung hat, die Bedingung zu beheben, die die Ausnahme verursacht hat, sollte er dies nichtcatch
tun, sondern muss lediglich wissen, was passiert ist. Aufruf einer Funktion wie:Innerhalb einer
when
Klausel kann die Factory-Funktion erkennen, dass etwas passiert ist.quelle