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?

Author: Nerdroid, 2009-04-08

12 answers

Tak, jest różnica;

  • throw ex resetuje ślad stosu (aby twoje błędy wyglądały na pochodzące z HandleException)
  • 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;
        }
    }
    
 715
Author: Marc Gravell,
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?

 102
Author: Shaul Behr,
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).

 44
Author: Jeppe Stig Nielsen,
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.

 8
Author: GR7,
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 # .

Throw vs Throw ex

 8
Author: Shivprasad Koirala,
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

Tutaj wpisz opis obrazka

Po drugie.. pozwala zrozumieć przez rzut ex. Wystarczy zastąpić throw z throw ex W m2 metoda catch block. jak poniżej.

Tutaj wpisz opis obrazka

Wyjście kodu throw ex jest jak poniżej..

Tutaj wpisz opis obrazka

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.

 7
Author: Mahesh,
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 instrukcji throw bez określania wyjątku.

Źródło: https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2200

 5
Author: Arman Sahakyan,
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.

 4
Author: Lucero,
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);
 3
Author: Aaaaaaaa,
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
    }
}
 0
Author: Charles Owen,
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.

 0
Author: Maksud,
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;
}
  1. Jeśli wszystkie linie 1 ,2 i 3 są skomentowane - Output-inner ex

  2. Jeśli wszystkie linie 2 i 3 są skomentowane - Output-inner ex System.DevideByZeroException: {"próba podzielenia przez zero."}---------

  3. Jeśli wszystkie linie 1 i 2 są skomentowane - Output-inner ex System.Wyjątek: devide by 0 ----

  4. 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;

 -1
Author: Bhanu pratap,
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