Okay, let me take a stab at it. The difference between throw and throw ex is already explained in Is there a difference between "throw" and "throw ex"? but I'll try to put it in more clear terms to fit the narrative of this question.
throw ex: Rethrows the exception from this point and resets the stack trace.throw: Rethrows the exception from this point and maintains the stack trace.
Let's look at the code in question:
private static void DummyWork()
{
try
{
throw new Exception("dummy"); // Line 21
}
catch (Exception ex)
{
throw; // Line 25
}
}
Here, whether we use throw or throw ex, the stack trace will always be:
at Program.DummyWork() in ...:line 25
at Program.Main() in ...:line 9
Why "line 25"?
Because both throw and throw ex rethrow the exception from that point.
Why is there no difference in this case?
Because there aren't any more stack frames in the stack trace to reset.
How can we see the difference?
Well, let's add another level to generate another stack frame. The code would be something like this:
private static void DummyWork()
{
try
{
MoreDummyWork(); // Line 21
}
catch (Exception ex)
{
throw; //Line 25
}
}
private static void MoreDummyWork()
{
throw new Exception("dummy"); // Line 31
}
Here, we can clearly see the difference. If we use throw, the stack trace is the following:
at Program.MoreDummyWork() in ...:line 31
at Program.DummyWork() in ...:line 25
at Program.Main() in ...:line 9
But if we use throw ex, the stack trace becomes:
at Program.DummyWork() in ...:line 25
at Program.Main() in ...:line 9
Okay, you say both will throw the exception from that point. What if I want to maintain the original line number?
In this case, you can use ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); as explained in How to rethrow InnerException without losing stack trace in C#?