Czy jest różnica między " rzucać "i" rzucać ex"?
Są posty, które pytają, jaka jest różnica między tymi dwoma już.
(dlaczego muszę o tym w ogóle wspominać...)
Ale moje pytanie jest INNE w sposób, który nazywam "throw ex" w innej metodzie obsługi błędu podobnego do Boga .
public class Program {
public static void Main(string[] args) {
try {
// something
} catch (Exception ex) {
HandleException(ex);
}
}
private static void HandleException(Exception ex) {
if (ex is ThreadAbortException) {
// ignore then,
return;
}
if (ex is ArgumentOutOfRangeException) {
// Log then,
throw ex;
}
if (ex is InvalidOperationException) {
// Show message then,
throw ex;
}
// and so on.
}
}
Jeśli {[1] } zostały użyte w Main
, to użyłbym throw;
, aby zmienić błąd.
Ale w powyższym prostym kodzie wszystkie wyjątki przechodzą przez HandleException
Czy throw ex;
ma taki sam efekt jak wywołanie throw
Kiedy wywołane wewnątrz HandleException
?
12 answers
Tak, jest różnica;
-
throw ex
resetuje ślad stosu (aby twoje błędy wyglądały na pochodzące zHandleException
) -
throw
nie - oryginalny sprawca zostałby zachowany.static void Main(string[] args) { try { Method2(); } catch (Exception ex) { Console.Write(ex.StackTrace.ToString()); Console.ReadKey(); } } private static void Method2() { try { Method1(); } catch (Exception ex) { //throw ex resets the stack trace Coming from Method 1 and propogates it to the caller(Main) throw ex; } } private static void Method1() { try { throw new Exception("Inside Method1"); } catch (Exception) { throw; } }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-23 10:23:44
(pisałem wcześniej, a @ Marc Gravell poprawił mnie)
Oto demonstracja różnicy:
static void Main(string[] args) {
try {
ThrowException1(); // line 19
} catch (Exception x) {
Console.WriteLine("Exception 1:");
Console.WriteLine(x.StackTrace);
}
try {
ThrowException2(); // line 25
} catch (Exception x) {
Console.WriteLine("Exception 2:");
Console.WriteLine(x.StackTrace);
}
}
private static void ThrowException1() {
try {
DivByZero(); // line 34
} catch {
throw; // line 36
}
}
private static void ThrowException2() {
try {
DivByZero(); // line 41
} catch (Exception ex) {
throw ex; // line 43
}
}
private static void DivByZero() {
int x = 0;
int y = 1 / x; // line 49
}
A oto wyjście:
Exception 1:
at UnitTester.Program.DivByZero() in <snip>\Dev\UnitTester\Program.cs:line 49
at UnitTester.Program.ThrowException1() in <snip>\Dev\UnitTester\Program.cs:line 36
at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 19
Exception 2:
at UnitTester.Program.ThrowException2() in <snip>\Dev\UnitTester\Program.cs:line 43
at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 25
Widać, że w wyjątku 1 ślad stosu wraca do metody DivByZero()
, podczas gdy w wyjątku 2 tak nie jest.
Zwróć jednak uwagę, że numer linii pokazany w ThrowException1()
i ThrowException2()
jest numerem linii throw
, , a nie numerem linii wywołania do DivByZero()
, co prawdopodobnie ma teraz sens że trochę o tym myślę...
Wyjście w trybie Release
Wyjątek 1:
at ConsoleAppBasics.Program.ThrowException1()
at ConsoleAppBasics.Program.Main(String[] args)
Wyjątek 2:
at ConsoleAppBasics.Program.ThrowException2()
at ConsoleAppBasics.Program.Main(String[] args)
Czy zachowuje oryginalną stackTrace tylko w trybie debugowania?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 22:10:02
Inne odpowiedzi są całkowicie poprawne, ale ta odpowiedź zapewnia dodatkowe detalis, myślę.
Rozważ ten przykład:
using System;
static class Program {
static void Main() {
try {
ThrowTest();
} catch (Exception e) {
Console.WriteLine("Your stack trace:");
Console.WriteLine(e.StackTrace);
Console.WriteLine();
if (e.InnerException == null) {
Console.WriteLine("No inner exception.");
} else {
Console.WriteLine("Stack trace of your inner exception:");
Console.WriteLine(e.InnerException.StackTrace);
}
}
}
static void ThrowTest() {
decimal a = 1m;
decimal b = 0m;
try {
Mult(a, b); // line 34
Div(a, b); // line 35
Mult(b, a); // line 36
Div(b, a); // line 37
} catch (ArithmeticException arithExc) {
Console.WriteLine("Handling a {0}.", arithExc.GetType().Name);
// uncomment EITHER
//throw arithExc;
// OR
//throw;
// OR
//throw new Exception("We handled and wrapped your exception", arithExc);
}
}
static void Mult(decimal x, decimal y) {
decimal.Multiply(x, y);
}
static void Div(decimal x, decimal y) {
decimal.Divide(x, y);
}
}
Jeśli odkomentujesz linię throw arithExc;
, twoje wyjście to:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:\somepath\Program.cs:line 44
at Program.Main() in c:\somepath\Program.cs:line 9
No inner exception.
Z pewnością straciłeś informacje o tym, gdzie doszło do tego wyjątku. Jeśli zamiast tego użyjesz linii throw;
, otrzymasz to:
Handling a DivideByZeroException.
Your stack trace:
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.Divide(Decimal d1, Decimal d2)
at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
at Program.ThrowTest() in c:\somepath\Program.cs:line 46
at Program.Main() in c:\somepath\Program.cs:line 9
No inner exception.
To jest o wiele lepsze, ponieważ teraz widzisz, że to metoda Program.Div
sprawiła Ci problemy. Ale nadal trudno sprawdź, czy ten problem pochodzi z linii 35 lub linii 37 w bloku try
.
Jeśli użyjesz trzeciej alternatywy, zawijając zewnętrzny wyjątek, nie utracisz żadnych informacji:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:\somepath\Program.cs:line 48
at Program.Main() in c:\somepath\Program.cs:line 9
Stack trace of your inner exception:
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.Divide(Decimal d1, Decimal d2)
at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
at Program.ThrowTest() in c:\somepath\Program.cs:line 35
W szczególności widać, że to linia 35 prowadzi do problemu. Wymaga to jednak, aby ludzie przeszukali InnerException
i wydaje się, że korzystanie z wewnętrznych WYJĄTKÓW w prostych przypadkach jest nieco pośrednie.
W ten wpis na blogu zachowują numer linii (linia bloku try) wywołując (poprzez odbicie) metodę internal
intance InternalPreserveStackTrace()
na obiekcie Exception
. Ale nie jest miło używać takiego reflection (. NET Framework może kiedyś zmienić swoich internal
członków bez ostrzeżenia).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 22:21:48
Kiedy to zrobisz throw ex
, wyrzucony wyjątek staje się "oryginalnym". Więc wszystkie poprzednie śledzenie stosu nie będzie tam.
Jeśli zrobisz throw
, wyjątek po prostu przejdzie W Dół Linii i otrzymasz pełny ślad stosu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-25 18:15:56
Throw zachowuje ślad stosu. Więc powiedzmy, że Source1 rzuca Error1, jego złapany przez Source2 i Source2 mówi throw, wtedy błąd Source1 + błąd Source2 będzie dostępny w śledzeniu stosu.
Throw ex nie zachowuje śladu stosu. Tak więc wszystkie błędy Source1 zostaną wymazane i tylko błąd Source2 zostanie wysłany do klienta.
Czasami po prostu czytanie rzeczy nie są jasne, sugerowałoby, aby obejrzeć To demo wideo, aby uzyskać większą jasność, Throw vs Throw ex w C # .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-19 03:09:37
Let ' s understand the difference between throw and throw ex. Słyszałem, że w wielu wywiadach z. Net jest to często zadawane pytanie.
Aby dać przegląd tych dwóch terminów, throw I throw ex są używane do zrozumienia, gdzie wystąpił wyjątek. Throw ex przepisuje ślad stosu wyjątku niezależnie od tego, gdzie faktycznie został wyrzucony.
Spójrzmy na przykład.
Let ' s understand first Throw.
static void Main(string[] args) {
try {
M1();
} catch (Exception ex) {
Console.WriteLine(" -----------------Stack Trace Hierarchy -----------------");
Console.WriteLine(ex.StackTrace.ToString());
Console.WriteLine(" ---------------- Method Name / Target Site -------------- ");
Console.WriteLine(ex.TargetSite.ToString());
}
Console.ReadKey();
}
static void M1() {
try {
M2();
} catch (Exception ex) {
throw;
};
}
static void M2() {
throw new DivideByZeroException();
}
Wyjście powyższego jest poniżej.
Pokazuje pełną hierarchię i nazwę metody, w której faktycznie został wyrzucony wyjątek.. jest to M2 - > M2. wraz z numerami linii
Po drugie.. pozwala zrozumieć przez rzut ex. Wystarczy zastąpić throw z throw ex W m2 metoda catch block. jak poniżej.Wyjście kodu throw ex jest jak poniżej..
Możesz zobaczyć różnicę w wyjściu.. throw ex po prostu ignoruje całą poprzednią hierarchię i resetuje ślad stosu z linia / metoda, w której zapisywany jest throw ex.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 22:11:02
Microsoft Docs oznacza :
Po wyrzuceniu wyjątku część informacji, którą niesie, to ślad stosu. Ścieżka stosu jest listą hierarchii wywołań metod, która zaczyna się od metody, która rzuca wyjątek, a kończy na metodzie, która wychwytuje wyjątek. Jeśli wyjątek zostanie ponownie wyrzucony przez podanie wyjątku w instrukcji
throw
, ślad stosu zostanie ponownie uruchomiony przy bieżącej metodzie i liście wywołań metod między oryginalną metodą to wyrzuciło wyjątek i bieżąca metoda zostanie utracona. Aby zachować oryginalne informacje o śledzeniu stosu z wyjątkiem, użyj instrukcjithrow
bez określania wyjątku.
Źródło: https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2200
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-11 00:25:25
Nie, spowoduje to, że wyjątek będzie miał inny ślad stosu. Tylko użycie obiektu throw
bez żadnego wyjątku w funkcji obsługi catch
pozostawi ślad stosu bez zmian.
Możesz chcieć zwrócić wartość logiczną z HandleException, niezależnie od tego, czy wyjątek ma zostać usunięty, czy nie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-08 14:26:59
Spójrz tutaj: http://blog-mstechnology.blogspot.de/2010/06/throw-vs-throw-ex.html
Rzut :
try
{
// do some operation that can fail
}
catch (Exception ex)
{
// do some local cleanup
throw;
}
Zachowuje informacje o stosie z wyjątkiem
To się nazywa "Rethrow"
Jeśli chcesz rzucić nowy wyjątek,
throw new ApplicationException("operation failed!");
Rzut Ex :
try
{
// do some operation that can fail
}
catch (Exception ex)
{
// do some local cleanup
throw ex;
}
Nie wyśle informacji o stosie z wyjątkiem
Nazywa się to "łamaniem stosu"
Jeśli chcesz rzucić nowy wyjątek,
throw new ApplicationException("operation failed!",ex);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 22:13:53
Aby dać ci inną perspektywę na ten temat, użycie throw jest szczególnie przydatne, jeśli dostarczasz klientowi API i chcesz dostarczyć szczegółowe informacje o śledzeniu stosu dla swojej biblioteki wewnętrznej. Używając throw tutaj, uzyskałbym ślad stosu w tym przypadku Biblioteki System.IO.File dla pliku.Usunąć Jeśli użyję throw ex, informacja ta nie zostanie przekazana mojemu handlerowi.
static void Main(string[] args) {
Method1();
}
static void Method1() {
try {
Method2();
} catch (Exception ex) {
Console.WriteLine("Exception in Method1");
}
}
static void Method2() {
try {
Method3();
} catch (Exception ex) {
Console.WriteLine("Exception in Method2");
Console.WriteLine(ex.TargetSite);
Console.WriteLine(ex.StackTrace);
Console.WriteLine(ex.GetType().ToString());
}
}
static void Method3() {
Method4();
}
static void Method4() {
try {
System.IO.File.Delete("");
} catch (Exception ex) {
// Displays entire stack trace into the .NET
// or custom library to Method2() where exception handled
// If you want to be able to get the most verbose stack trace
// into the internals of the library you're calling
throw;
// throw ex;
// Display the stack trace from Method4() to Method2() where exception handled
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 22:15:11
Lepiej używać throw
zamiast throw ex
.
Throw ex resetuje oryginalny ślad stosu i nie może zostać znaleziony poprzedni ślad stosu.
Jeśli użyjemy throw, uzyskamy pełny ślad stosu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-03 02:37:41
int a = 0;
try {
int x = 4;
int y ;
try {
y = x / a;
} catch (Exception e) {
Console.WriteLine("inner ex");
//throw; // Line 1
//throw e; // Line 2
//throw new Exception("devide by 0"); // Line 3
}
} catch (Exception ex) {
Console.WriteLine(ex);
throw ex;
}
-
Jeśli wszystkie linie 1 ,2 i 3 są skomentowane - Output-inner ex
Jeśli wszystkie linie 2 i 3 są skomentowane - Output-inner ex System.DevideByZeroException: {"próba podzielenia przez zero."}---------
Jeśli wszystkie linie 1 i 2 są skomentowane - Output-inner ex System.Wyjątek: devide by 0 ----
Jeśli wszystkie linie 1 i 3 są skomentowane - Output-inner ex System.DevideByZeroException: {"próba podziału przez zero."}---------
I StackTrace zostanie zresetowane w przypadku throw ex;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 22:20:01