Freitag, 5. Dezember 2008

throw ex vs throw

Es ist eigentlich ein alter Hut, der Unterschied zwischen throw ex und throw sollte jedem bekannt sein. Throw ex schneidet den alten Stack Trace ab und verpackt sozusagen den Fehler neu, Throw hingegen nicht.

Aber dennoch halten sich irgendwie hartnäckig gegenteilige Meinungen, vermutlich aus den Gegenbenheiten aus Java resultierend, aber ich habe auch schon einige ellenlange Threads gelesen in denen das vollkommen Falsche dargelegt wurde, bis hin zu Projektleitern die von einem Verlangen ein ganzes Projekt umzuprogrammieren, weil sie der Meinung wären es wäre genau anders herum. 

Den Beweis zu führen ist recht simpel, entweder man schaut sich den MSIL Code an und erkennt das throw zu einem rethrow compiliert, während throw ex, ein throw ex bleibt. Oder aber man testet es einfach mit einem Programm folgender Art selber aus, um auch den letzten Kritiker hoffentlich verstummen zu lassen...

   1:  class ThrowVsThrowEx
   2:  {
   3:     static void Main(string[] args)
   4:     {
   5:        try
   6:        {
   7:           ReThrow();
   8:        }
   9:        catch(Exception ex)
  10:        {
  11:           Console.WriteLine("ReThrow sent: " + ex.ToString());
  12:        }
  13:   
  14:        Console.Write(System.Environment.NewLine);
  15:   
  16:        try
  17:        {
  18:           ThrowNew();
  19:        }
  20:        catch (Exception ex)
  21:        {
  22:           Console.WriteLine("ThrowNew sent: " + ex.ToString());
  23:        }
  24:   
  25:        Console.ReadLine();
  26:     }
  27:   
  28:     static void ReThrow()
  29:     {
  30:        try
  31:        {
  32:           DontCallMe();
  33:        }
  34:        catch
  35:        {
  36:           throw;
  37:        }
  38:     }
  39:   
  40:     static void ThrowNew()
  41:     {
  42:        try
  43:        {
  44:           DontCallMe();
  45:        }
  46:        catch(Exception ex)
  47:        {
  48:           throw ex;
  49:        }
  50:     }
  51:   
  52:     static void DontCallMe()
  53:     {
  54:        throw new ApplicationException("I said don't call me!!");
  55:     }
  56:  }


Ergebnis von throw:

ReThrow sent: System.ApplicationException: I said don't call me!! at DemoExceptions.ThrowVsThrowEx.DontCallMe() in C:\Projects\DemoExceptions\D emoExceptions\ThrowVsThrowEx.cs:line 54 at DemoExceptions.ThrowVsThrowEx.ReThrow() in C:\Projects\DemoExceptions\Demo Exceptions\ThrowVsThrowEx.cs:line 36 at DemoExceptions.ThrowVsThrowEx.Main(String[] args) in C:\Projects\DemoExcep tions\DemoExceptions\ThrowVsThrowEx.cs:line 7


und das Ergebnis von throw ex:

ThrowNew sent: System.ApplicationException: I said don't call me!! at DemoExceptions.ThrowVsThrowEx.ThrowNew() in C:\Projects\DemoExceptions\Dem oExceptions\ThrowVsThrowEx.cs:line 48 at DemoExceptions.ThrowVsThrowEx.Main(String[] args) in C:\Projects\DemoExcep tions\DemoExceptions\ThrowVsThrowEx.cs:line 18


Wunderbar zu erkennen wie throw ex den Ursprung abgeschnitten hat und stattdessen bei sich "selbst" anfängt... keine Worte :)

3 Kommentare:

Anonym hat gesagt…

Du solltest eher statt

throw ex;

das so machen:

throw new Exception( "lalala", ex );

BBo hat gesagt…

Hallo Uwe,

für den Fall, dass du die Exception kapseln möchtest, ist das absolut eine gute Idee.
Allerdings wollte tropensturm wohl eher darauf hinaus, dass nach wie vor viele leute das "throw ex;" anstelle eines einfachen "throw;" verwenden und sich somit den in der Exception enthaltenen StackTrace verfälschen.

Für eine Kapslung: deine Methodik
Für einfaches weiterreichen: throw;

Gruß,
BBo

Tropensturm hat gesagt…

Das erhält zwar den Stacktrace, hat aber einen rundimentären Unterschied zu throw ex, als auch throw, es verändert den Exception Typ!

Im Beispiel werfe ich eine ApplicationException, und fange sie an irgendeiner Stelle generell mit Exception ab. Sowohl throw, als auch throw ex, werfen eine ApplicationException weiter. Mit unterschiedlich langen Stacktraces. Jedoch durch das new Exception Konstrukt wird aus der ApplicationException eine Exception!

Das "KANN" erwünscht sein, wenn man z.B. Exceptions gleichschalten will mit einem eigenen Exception Typ, kann aber auch völlig unerwünscht sein. Natürlich kann man auch ein umfangreiches Handling mit mehreren Catchblöcken machen. Jedoch erscheint mir für diesen Fall throw deutlich handlicher.
Aber wie erwähnt kommt es auf den Anwendungsfall meiner Meinung nach an. Jedenfalls muß man wissen was man tut, was man da macht.

Ansonsten ging es mir nur generell um den Unterschied zwischen throw und throw ex wie schon von BBo erklärt.