views:

331

answers:

3

Hi! I have this code

try
{
  //AN EXCEPTION IS GENERATED HERE!!!
}
catch  
{
   SqlService.RollbackTransaction();
   throw;
}

Code above is called in this code

try
{
  //HERE IS CALLED THE METHOD THAT CONTAINS THE CODE ABOVE
}
catch (Exception ex)
{
   HandleException(ex);
}

The exception passed as parameter to the method "HandleException" contains the line number of the "throw" line in the stack trace instead of the real line where the exception was generated. Anyone knows why this could be happening?

EDIT1 Ok, thanks to all for your answers. I changed the inner catch for


catch(Exception ex)
{
    SqlService.RollbackTransaction();
    throw new Exception("Enrollment error", ex);
}

Now I have the correct line on the stack trace, but I had to create a new exception. I was hoping to find a better solution :-(

EDIT2 Maybe (if you have 5 minutes) you could try this scenario in order to check if you get the same result, not very complicated to recreate.

+3  A: 

C# stack traces are generated at throw time, not at exception creation time.

This is different from Java, where the stack traces are filled at exception creation time.

This is apparently by design.

Randolpho
Yes, but `throw;` preserves the original stack trace.
SLaks
@SLaks: Excellent point. Based on @Andy Shellam's comment to the original question, I'm starting to think maybe the original exception is getting swallowed by an exception in the catch block.
Randolpho
+2  A: 

Does the date/time stamp of your .pdb file match your .exe/.dll file? If not, it could be that the compilation is not in "debug mode" which generates a fresh .pdb file on each build. The pdb file has the accurate line numbers when exceptions occur.

Look into your compile settings to make sure the debug data is generated, or if you're in a test/production environment, check the .pdb file to make sure the timestamps match.

Dillie-O
interesting possible side-answer. +1
Randolpho
Has happened to me on more than one occasion. 8^D
Dillie-O
Dates match, just double checked
Claudio Redi
+4  A: 

Yes, this is a limitation in the exception handling logic. If a method contains more than one throw statement that throws an exception then you'll get the line number of the last one that threw. This example code reproduces this behavior:

using System;

class Program {
    static void Main(string[] args) {
        try {
            Test();
        }
        catch (Exception ex) {
            Console.WriteLine(ex.ToString());
        }
        Console.ReadLine();
    }
    static void Test() {
        try {
            throw new Exception();  // Line 15
        }
        catch {
            throw;                  // Line 18
        }
    }
}

Output:

System.Exception: Exception of type 'System.Exception' was thrown.
   at Program.Test() in ConsoleApplication1\Program.cs:line 18
   at Program.Main(String[] args) in ConsoleApplication1\Program.cs:line 6

The work-around is simple, just use a helper method to run the code that might throw an exception.

Like this:

static void Test() {
    try {
        Test2();                // Line 15
    }
    catch {
        throw;                  // Line 18
    }
}
static void Test2() {
    throw new Exception();      // Line 22
}
Hans Passant
Thanks! Not sure what you mean by helper method. The exception on my code and on your code is generated on a separated method.
Claudio Redi
@Claudio: I updated the post to show what the helper method looks like.
Hans Passant