What is the difference between "throw" and "throw ex"?

16

I saw that C # allows you to do ...

try
{
    //algum código
}
catch
{
    throw;
}

too ...

try
{
    //algum código
}
catch (Exception ex)
{
    throw ex;
}

and ...

try
{
    //algum código
}
catch (Exception)
{
    throw;
}

My questions are: where is the exception thrown in throw , what is the difference between the three and if any, what is the best situation to use each?

    
asked by anonymous 28.09.2014 / 18:06

1 answer

20

The first and last examples in practice are identical if you are using only C # as the language in your application. Not specifying what to catch indicates that you are capturing Exception . That is, any exception. There is a difference in one case.

If you are using C ++ or another language that allows you to throw anything (a string, a number, any data structure) and have C # catch this exception, it will work in the first example. As he does not specify what to take, he takes anything. But it will not work in the last example, after all you are specifying that you want exceptions of type Exception and, of course, any exceptions inherited directly or indirectly from Exception .

C # only allows you to throw exceptions of this type and their derivatives. Then an unspecified catch will catch any exception thrown by C #, which is the same as catch (Exception ex) .

You should always use throw; .

When you issue a throw ex; you are stopping the exception there by doing some operation (in your case neither this is done but I will consider that it is just to be an example) and then throws another exception from then on. It loses information where the actual exception actually came from and launches a new . It is as if a new problem has occurred. There is hardly a case where this is desirable. In your example you will probably catch a more specific exception and throw a Exception which is the exception you captured and very general that is not desirable (I answer a lot about this, my most recent response on the subject is There are some drawbacks in always capturing Exception and not something more specific? , there is a link for other answers).

By issuing only throw; you are passing the same exception forward, so another snippet of code (where catch exists) can capture and know what to do with the original exception preserving all necessary information, especially the stack trace .

Whenever you throw an exception it will stop where you find the first catch . Although rare, this may be soon in the same method that the exception was thrown, it can be in the method caller, it can be in the previous method, and the previous one to it and so on, until it can be in Main() and even if it does not find a catch somewhere it will fall into an implicit%% "hidden" by the environment. When you throw a throw you can not be sure where it will be captured unless it is a very small application developed by you and does not usually add new things to it.

The only place an exception stops is catch (of course a catch is still a finally . I would say this holds true for any language, at least it is for all I know.

Note that if you use the code presented in the question in real code it does not make any sense. You do not have to catch an exception, do nothing with it, and pass it on to another catch to take some action.

I found a example in SO that helps you understand better:

using System;

public class Program {
     public 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
    }
}

See running on .NET Fiddle . Also put it on GitHub for future reference .

The output would be:

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

Did you notice that the second with catch lost important information from where the exception actually occurred? And then you're like "dumb cockroach" trying to find something in a method. Of course it may seem easy to find the bug but remember that this is a simple example code, you might lose several levels of method calls, make the methods more complex.

CIL code generated when using throw ex; :

catch [mscorlib]System.Exception {
    IL_000b:  stloc.0
    IL_000c:  nop
    IL_000d:  ldloc.0
    IL_000e:  throw
}

And with throw ex; :

 catch [mscorlib]System.Exception {
    IL_000b:  stloc.0
    IL_000c:  nop
    IL_000d:  rethrow
 }

The actual instruction to be executed is quite different. The first code throws an exception in a normal way using as an argument what's in the stack and the second does a completely different operation. Explicitly re throwing the active exception (note that no argument is loaded with the throw; statement as done in the previous example).

    
28.09.2014 / 18:15