was ist der Unterschied zwischen
try { ... }
catch{ throw }
und
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Unabhängig davon, dass die zweite eine Nachricht zeigt?
was ist der Unterschied zwischen
try { ... }
catch{ throw }
und
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Unabhängig davon, dass die zweite eine Nachricht zeigt?
Antworten:
throw; Löst die ursprüngliche Ausnahme erneut aus und behält die ursprüngliche Stapelverfolgung bei.
throw ex;Löst die ursprüngliche Ausnahme aus, setzt jedoch die Stapelverfolgung zurück und zerstört alle Stapelverfolgungsinformationen bis zu Ihrem catchBlock.
throw ex;throw new Exception(ex.Message);ist noch schlimmer. Es wird eine brandneue ExceptionInstanz erstellt, wobei die ursprüngliche Stapelverfolgung der Ausnahme sowie deren Typ verloren gehen. (zB IOException).
Darüber hinaus enthalten einige Ausnahmen zusätzliche Informationen (z ArgumentException.ParamName. B. ).
throw new Exception(ex.Message); wird auch diese Informationen zerstören.
In bestimmten Fällen möchten Sie möglicherweise alle Ausnahmen in ein benutzerdefiniertes Ausnahmeobjekt einschließen, damit Sie zusätzliche Informationen darüber bereitstellen können, was der Code beim Auslösen der Ausnahme getan hat.
Dazu definieren Sie eine neue Klasse, die erbt Exception, fügen Sie alle vier Ausnahme Konstrukteuren und optional eine zusätzliche Konstruktor, der eine nimmt InnerExceptionsowie weitere Informationen und Ihre neue Ausnahmeklasse werfen, vorbei exals InnerExceptionParameter . Durch Übergeben des Originals InnerExceptionbehalten Sie alle Eigenschaften der ursprünglichen Ausnahme bei, einschließlich der Stapelverfolgung.
throw new MyCustomException(myMessage, ex);natürlich sein sollte.
ex.Message, das ist schlimmer.
[Serializable()].
throw;die tatsächliche Zeilennummer, bei der die Ausnahme aufgetreten ist, durch die Zeilennummer von ersetzen throw;. Wie schlagen Sie vor, damit umzugehen? stackoverflow.com/questions/2493779/…
Der erste behält die ursprüngliche Stapelspur bei:
try { ... }
catch
{
// Do something.
throw;
}
Mit der zweiten Option können Sie den Typ der Ausnahme und / oder die Nachricht und andere Daten ändern:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
Es gibt auch einen dritten Weg, auf dem Sie eine innere Ausnahme passieren:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
Ich würde empfehlen:
Ein weiterer Punkt, den ich von niemandem gesehen habe:
Wenn Sie in Ihrem catch {} -Block nichts tun, ist es sinnlos, einen Versuch zu unternehmen ... catch. Ich sehe das die ganze Zeit:
try
{
//Code here
}
catch
{
throw;
}
Oder schlimmer:
try
{
//Code here
}
catch(Exception ex)
{
throw ex;
}
Das Schlimmste noch:
try
{
//Code here
}
catch(Exception ex)
{
throw new System.Exception(ex.Message);
}
throwLöst die abgefangene Ausnahme erneut aus, wobei die Stapelverfolgung beibehalten wird, während throw new Exceptioneinige Details der abgefangenen Ausnahme verloren gehen.
Normalerweise würden Sie throweine Ausnahme selbst protokollieren, ohne sie zu diesem Zeitpunkt vollständig zu behandeln.
BlackWasp hat einen guten Artikel mit dem Titel Throwing Exceptions in C # .
Durch das Auslösen einer neuen Ausnahme wird die aktuelle Stapelverfolgung weggeblasen.
throw;behält die ursprüngliche Stapelverfolgung bei und ist fast immer nützlicher. Die Ausnahme von dieser Regel besteht darin, dass Sie die Ausnahme in eine eigene benutzerdefinierte Ausnahme einschließen möchten. Sie sollten dann tun:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
throwdient zum erneuten Auslösen einer abgefangenen Ausnahme. Dies kann nützlich sein, wenn Sie etwas mit der Ausnahme tun möchten, bevor Sie es an die Aufrufkette weiterleiten.
Bei Verwendung throwohne Argumente bleibt der Aufrufstapel für Debugging-Zwecke erhalten.
In Ihrem zweiten Beispiel wird die Stapelverfolgung der Ausnahme zurückgesetzt. Die erste bewahrt die Ursprünge der Ausnahme am genauesten. Außerdem haben Sie den Originaltyp ausgepackt, der entscheidend dafür ist, was tatsächlich schief gelaufen ist ... Wenn der zweite für die Funktionalität erforderlich ist - z. B. um erweiterte Informationen hinzuzufügen oder mit einem speziellen Typ wie einer benutzerdefinierten 'HandleableException' neu zu verpacken, dann seien Sie einfach Stellen Sie sicher, dass auch die InnerException-Eigenschaft festgelegt ist!
Der wichtigste Unterschied besteht darin, dass der zweite Ausdruck die Art der Ausnahme löscht. Der Ausnahmetyp spielt eine wichtige Rolle beim Abfangen von Ausnahmen:
public void MyMethod ()
{
// both can throw IOException
try { foo(); } catch { throw; }
try { bar(); } catch(E) {throw new Exception(E.message); }
}
(...)
try {
MyMethod ();
} catch (IOException ex) {
Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
Console.WriteLine ("Other error"); // [2]
}
Wenn foo()geworfen wird IOException, [1]fängt catch block eine Ausnahme ab. Aber wenn es bar()geworfen wird IOException, wird es in eine einfache ExceptionAmeise umgewandelt, die nicht vom [1]Fangblock gefangen wird .
throw oder throw ex, beide werden verwendet, um die Ausnahme zu werfen oder erneut zu werfen. Wenn Sie einfach die Fehlerinformationen protokollieren und keine Informationen an den Anrufer zurücksenden möchten, protokollieren Sie den Fehler einfach in catch and Leave. Für den Fall, dass Sie dem Anrufer, den Sie werfen oder werfen, einige aussagekräftige Informationen über die Ausnahme senden möchten. Der Unterschied zwischen throw und throw ex besteht nun darin, dass throw die Stapelverfolgung und andere Informationen beibehält, aber throw ex ein neues Ausnahmeobjekt erstellt und daher die ursprüngliche Stapelverfolgung verloren geht. Wann sollten wir also throw und throw e verwenden? Es gibt immer noch einige Situationen, in denen Sie möglicherweise eine Ausnahme erneut auslösen möchten, um die Call-Stack-Informationen zurückzusetzen. Wenn sich die Methode beispielsweise in einer Bibliothek befindet und Sie die Details der Bibliothek vor dem aufrufenden Code verbergen möchten, Sie möchten nicht unbedingt, dass der Aufrufstapel Informationen zu privaten Methoden in die Bibliothek enthält. In diesem Fall können Sie Ausnahmen in den öffentlichen Methoden der Bibliothek abfangen und sie dann erneut auslösen, sodass der Aufrufstapel bei diesen öffentlichen Methoden beginnt.
Werfen; Die ursprüngliche Ausnahme erneut auslösen und den Ausnahmetyp beibehalten.
Neue Ausnahme auslösen (); Werfen Sie den ursprünglichen Ausnahmetyp erneut und setzen Sie den Ausnahmestapel-Trace zurück
Ex werfen; Setzen Sie den Ausnahmestapel-Trace zurück und setzen Sie den Ausnahmetyp zurück
Keine der Antworten hier zeigt den Unterschied, was für Leute hilfreich sein könnte, die Schwierigkeiten haben, den Unterschied zu verstehen. Betrachten Sie diesen Beispielcode:
using System;
using System.Collections.Generic;
namespace ExceptionDemo
{
class Program
{
static void Main(string[] args)
{
void fail()
{
(null as string).Trim();
}
void bareThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw;
}
}
void rethrow()
{
try
{
fail();
}
catch (Exception e)
{
throw e;
}
}
void innerThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw new Exception("outer", e);
}
}
var cases = new Dictionary<string, Action>()
{
{ "Bare Throw:", bareThrow },
{ "Rethrow", rethrow },
{ "Inner Throw", innerThrow }
};
foreach (var c in cases)
{
Console.WriteLine(c.Key);
Console.WriteLine(new string('-', 40));
try
{
c.Value();
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
Welches erzeugt die folgende Ausgabe:
Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
--- End of inner exception stack trace ---
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Der bloße Wurf, wie in den vorherigen Antworten angegeben, zeigt deutlich sowohl die ursprüngliche Codezeile, die fehlgeschlagen ist (Zeile 12), als auch die beiden anderen Punkte, die im Aufrufstapel aktiv waren, als die Ausnahme auftrat (Zeilen 19 und 64).
Die Ausgabe des Re-Throw-Falls zeigt, warum dies ein Problem ist. Wenn die Ausnahme auf diese Weise erneut ausgelöst wird, enthält die Ausnahme nicht die ursprünglichen Stapelinformationen. Beachten Sie, dass nur der throw e(Zeile 35) und der äußerste Aufrufstapelpunkt (Zeile 64) enthalten sind. Es wäre schwierig, die fail () -Methode als Ursache des Problems aufzuspüren, wenn Sie auf diese Weise Ausnahmen auslösen.
Der letzte Fall (innerThrow) ist am ausführlichsten und enthält mehr Informationen als die oben genannten. Da wir eine neue Ausnahme instanziieren, haben wir die Möglichkeit, Kontextinformationen hinzuzufügen (die "äußere" Nachricht hier, aber wir können auch das .Data-Wörterbuch für die neue Ausnahme hinzufügen) sowie alle Informationen im Original beizubehalten Ausnahme (einschließlich Hilfelinks, Datenwörterbuch usw.).