211

What is the difference between

try { ... }
catch{ throw }

and

try{ ... }
catch(Exception e) {throw new Exception(e.message) }

regardless that the second shows a message.

Jim G.
  • 15,141
  • 22
  • 103
  • 166
Strider007
  • 4,615
  • 7
  • 25
  • 26
  • 70
    The second snippet is one of the most evil (but innocuous) lines of code I've ever seen. – SLaks Jun 08 '10 at 16:40
  • http://stackoverflow.com/questions/22623/net-throwing-exceptions-best-practices – dotjoe Jun 08 '10 at 16:43
  • 1
    Does this answer your question? [Is there a difference between "throw" and "throw ex"?](https://stackoverflow.com/questions/730250/is-there-a-difference-between-throw-and-throw-ex) – Jim G. Aug 18 '22 at 13:32

12 Answers12

349

throw; rethrows the original exception and preserves its original stack trace.

throw ex; throws the original exception but resets the stack trace, destroying all stack trace information until your catch block.


NEVER write throw ex;


throw new Exception(ex.Message); is even worse. It creates a brand new Exception instance, losing the original stack trace of the exception, as well as its type. (eg, IOException).
In addition, some exceptions hold additional information (eg, ArgumentException.ParamName).
throw new Exception(ex.Message); will destroy this information too.

In certain cases, you may want to wrap all exceptions in a custom exception object, so that you can provide additional information about what the code was doing when the exception was thrown.

To do this, define a new class that inherits Exception, add all four exception constructors, and optionally an additional constructor that takes an InnerException as well as additional information, and throw your new exception class, passing ex as the InnerException parameter. By passing the original InnerException, you preserve all of the original exception's properties, including the stack trace.

Community
  • 1
  • 1
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 26
    "throw new Exception(ex); is even worse.": I disagree on this one. Sometimes you want to change the type of an exception, and then keeping the original exception as inner exception is the best you can do. Though it should be `throw new MyCustomException(myMessage, ex);` of course. – Dirk Vollmar Jun 08 '10 at 16:36
  • 11
    @0xA3: I meant `ex.Message`, which _is_ worse. – SLaks Jun 08 '10 at 16:47
  • 6
    In addition to implementing the standard constructors, one should also make custom exceptions `[Serializable()]`. – Dirk Vollmar Jun 08 '10 at 16:56
  • Yes; I forgot to mention that. – SLaks Jun 08 '10 at 16:56
  • I guess it depends. Sometimes you know what the cause of the exceptions is and still want to hide the details of your implementation from the user. This way, you pass the message (which you know is okay) and make it seem like you were the source. Then: What 0xA3 said. – sunside Jun 08 '10 at 17:00
  • @Markus: **No**. _No No NO!_. _Always_ pass `InnerException`. It makes it infinitely easier to track down a problem if you know exactly what the exception came from. – SLaks Jun 08 '10 at 17:09
  • 27
    Yo dawg, we herd you like exceptions so we put an exception in yo’ exception so you can catch while you catch. – Darth Continent Oct 14 '11 at 13:48
  • 4
    @SLaks: When you `throw;` the actual line number where the exception occurred is replaced by the line number of `throw;`. How do you suggest handling that? http://stackoverflow.com/questions/2493779/wrong-line-number-on-stack-trace – Eric J. Jan 04 '13 at 18:39
  • That means I can never [*throw up*](http://stackoverflow.com/questions/549611)?? I have always wanted to *throw up* in my code :-( – Sнаđошƒаӽ Jan 23 '17 at 12:23
  • downvoting because throw; doesn't always preserve the stack trace, as Eric mentioned. – NH. Apr 04 '18 at 21:14
  • 2
    to follow-up on @DirkVollmar, if your code is sensitive and contains intellectual property or other sensitive data in the inner messages, you may intentionally want to mask any and all details of the inner exceptions in the api you expose. In this case throw new MyCustomException(myMessage) makes sense without providing the inner exception. – shelbypereira Dec 09 '19 at 12:39
  • @SLaks Hi mate, I saw in many examples in catch statement ppl are just making logging of an error and not throwing anyhing, is it useful to throw; exception further? I mean should we add throw; to catch statement anyway? – Roxy'Pro Dec 15 '19 at 23:53
  • @Roxy'Pro: Yes; if you're just logging the error, your callsite probably needs to know about it. – SLaks Jan 02 '20 at 16:05
45

The first preserves the original stacktrace:

try { ... }
catch
{
    // Do something.
    throw;
}

The second allows you to change the type of the exception and/or the message and other data:

try { ... } catch (Exception e)
{
    throw new BarException("Something broke!");
}

There's also a third way where you pass an inner exception:

try { ... }
catch (FooException e) {
    throw new BarException("foo", e);
} 

I'd recommend using:

  • the first if you want to do some cleanup in error situation without destroying information or adding information about the error.
  • the third if you want to add more information about the error.
  • the second if you want to hide information (from untrusted users).
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
13

One other point that I didn't see anyone make:

If you don't do anything in your catch {} block, having a try...catch is pointless. I see this all the time:

try 
{
  //Code here
}
catch
{
    throw;
}

Or worse:

try 
{
  //Code here
}
catch(Exception ex)
{
    throw ex;
}

Worst yet:

try 
{
  //Code here
}
catch(Exception ex)
{
    throw new System.Exception(ex.Message);
}
Marcie
  • 1,169
  • 1
  • 10
  • 17
13

None of the answers here show the difference, which could be helpful for folks struggling to understand the difference. Consider this sample code:

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());
            }
         }
      }
   }
}

Which generates the following output:

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

The bare throw, as indicated in the previous answers, clearly shows both the original line of code that failed (line 12) as well as the two other points active in the call stack when the exception occurred (lines 19 and 64).

The output of the rethrow case shows why it's a problem. When the exception is rethrown like this the exception won't include the original stack information. Note that only the throw e (line 35) and outermost call stack point (line 64) are included. It would be difficult to track down the fail() method as the source of the problem if you throw exceptions this way.

The last case (innerThrow) is most elaborate and includes more information than either of the above. Since we're instantiating a new exception we get the chance to add contextual information (the "outer" message, here but we can also add to the .Data dictionary on the new exception) as well as preserving all of the information in the original exception (including help links, data dictionary, etc.).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lee
  • 801
  • 1
  • 6
  • 20
  • Not sure why this was voted down without comments, since it says basically the same thing as the top answer but with more details. – Lee Nov 16 '20 at 07:44
10

Throwing a new Exception blows away the current stack trace.

throw; will retain the original stack trace and is almost always more useful. The exception to that rule is when you want to wrap the Exception in a custom Exception of your own. You should then do:

catch(Exception e)
{
    throw new CustomException(customMessage, e);
}
Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
4

throw rethrows the caught exception, retaining the stack trace, while throw new Exception loses some of the details of the caught exception.

You would normally use throw by itself to log an exception without fully handling it at that point.

BlackWasp has a good article sufficiently titled Throwing Exceptions in C#.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
3

throw is for rethrowing a caught exception. This can be useful if you want to do something with the exception before passing it up the call chain.

Using throw without any arguments preserves the call stack for debugging purposes.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
1

Your second example will reset the exception's stack trace. The first most accurately preserves the origins of the exception.

Also you've unwrapped the original type which is key in knowing what actually went wrong... If the second is required for functionality - e.g., to add extended information or rewrap with a special type such as a custom 'HandleableException' then just be sure that the InnerException property is set too!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Reddog
  • 15,219
  • 3
  • 51
  • 63
1

Throw;: Rethrow the original exception and keep the exception type.

Throw new exception();: Rethrow the original exception type and reset the exception stack trace

Throw ex;: Reset the exception stack trace and reset the exception type

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ararb78
  • 1,137
  • 5
  • 19
  • 44
0

If you want you can throw a new Exception, with the original one set as an inner exception.

apoorv020
  • 5,420
  • 11
  • 40
  • 63
0

Most important difference is that the second expression erases the type of the exception. And the exception type plays a vital role in catching exceptions:

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]
}

If foo() throws an IOException, the [1] catch block will catch the exception. But when bar() throws IOException, it will be converted to plain Exception and won't be caught by the [1] catch block.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

throw or throw ex, both are used to throw or rethrow the exception, when you just simply log the error information and don't want to send any information back to the caller you simply log the error in catch and leave.

But in case you want to send some meaningful information about the exception to the caller you use throw or throw ex. Now the difference between throw and throw ex is that throw preserves the stack trace and other information, but throw ex creates a new exception object and hence the original stack trace is lost.

So when should we use throw and throw e? There are still a few situations in which you might want to rethrow an exception like to reset the call stack information.

For example, if the method is in a library and you want to hide the details of the library from the calling code, you don’t necessarily want the call stack to include information about private methods within the library. In that case, you could catch exceptions in the library’s public methods and then rethrow them so that the call stack begins at those public methods.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Saket Choubey
  • 916
  • 6
  • 11