c# exception stack-trace

c# - Número de línea incorrecto en el seguimiento de la pila para la excepción lanzada dentro de la instrucción switch



exception stack-trace (1)

He intentado descompilar el ensamblaje y parece que el ensamblaje realiza una optimización en ambos modos. En particular, el segundo método se cambia:

private static void ThrowSomeException(int arg) { Console.WriteLine("arg = {0}", arg); switch (arg) { case 0: { throw new Exception("Line number = 16"); } case 1: { throw new Exception("Line number = 18"); } } throw new Exception("Line number = 20"); }

Así es como Telerik JustDecompile me dice que se ve el método, tanto en el modo Debug como en el modo Release. Es muy posible que si ve el ensamblaje en bruto, habrá una explicación adicional de por qué existe esta discrepancia.

No sé cómo continuar esto, pero creo que este es un problema muy interesante. Voy a marcar mi respuesta como Community Wiki, con la esperanza de que un esfuerzo de colaboración pueda resolver esto.

He hecho algunas pruebas más. He movido la función ThrowSomeException () a una clase separada y la hice no estática, y eso no cambió nada. Luego lo reescribí ligeramente para primero asignar la excepción a una variable y luego lanzarla por separado.

internal class Program { private static void Main() { Test test = new Test(); for (int i = 0; i < 3; i++) { try { test.ThrowSomeException(i); } catch (Exception exception) { Console.WriteLine(exception); } } } } public class Test { public void ThrowSomeException(int arg) { Console.WriteLine("arg = {0}", arg); switch (arg) { case 0: { Exception ex = new Exception("Line number = 36"); throw ex; } case 1: { Exception ex = new Exception("Line number = 41"); throw ex; } default: { Exception ex = new Exception("Line number = 46"); throw ex; } } } }

El código anterior tiene el siguiente resultado en el modo de depuración:

arg = 0 System.Exception: Line number = 36 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 40 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14 arg = 1 System.Exception: Line number = 41 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 45 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14 arg = 2 System.Exception: Line number = 46 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 47 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14

En el modo Release, la segunda excepción se lanza desde la línea 46 en lugar de 45. Este comportamiento es consistente para todas las versiones de .NET framework y todas las versiones de VS. A continuación voy a intentar hacer esto usando un proyecto de VB para ver si hace una diferencia.

Edición: usando el siguiente proyecto de VB en VS 2012:

Module Program Sub Main() Dim test As New Test() For i As Integer = 0 To 2 Try test.ThrowSomeException(i) Catch exception As Exception Console.WriteLine(exception) End Try Next End Sub End Module Public Class Test Public Sub ThrowSomeException(arg As Integer) Console.WriteLine("arg = {0}", arg) Select Case arg Case 0 If True Then Dim ex As New Exception("Line number = 22") Throw ex End If Case 1 If True Then Dim ex As New Exception("Line number = 27") Throw ex End If Case Else If True Then Dim ex As New Exception("Line number = 32") Throw ex End If End Select End Sub End Class

El problema no ocurre y los números de línea son consistentes.

También he probado directamente los ejecutables generados por la salida y he encontrado resultados aún más extraños. Esta es la salida del exe de depuración:

arg = 0 System.Exception: Line number = 36 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 40 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14 arg = 1 System.Exception: Line number = 41 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 45 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14 arg = 2 System.Exception: Line number = 46 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 47 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14

Y esta es la salida del modo de lanzamiento exe:

arg = 0 System.Exception: Line number = 36 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 41 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14 arg = 1 System.Exception: Line number = 41 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 42 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14 arg = 2 System.Exception: Line number = 46 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 37 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 14

Este no es el mismo resultado que usar el depurador para ejecutar esto.

Las pruebas rápidas als parecen indicar que las líneas adicionales entre la excepción y la declaración de lanzamiento (en este caso, una console.writeline () también afectan el resultado:

reescrito cambiar a esto:

switch (arg) { case 0: { Exception ex = new Exception("Line number = 37"); Console.WriteLine("case 0"); throw ex; } case 1: { Exception ex = new Exception("Line number = 43"); Console.WriteLine("case 1"); throw ex; } default: { Exception ex = new Exception("Line number = 49"); Console.WriteLine("case default"); throw ex; } }

da esta salida de lanzamiento de VS:

arg = 0 case 0 System.Exception: Line number = 37 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 43 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15 arg = 1 case 1 System.Exception: Line number = 43 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 49 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15 arg = 2 case default System.Exception: Line number = 49 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 51 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15

y esta salida desde la línea de comando:

arg = 0 case 0 System.Exception: Line number = 37 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 43 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15 arg = 1 case 1 System.Exception: Line number = 43 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 45 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15 arg = 2 case default System.Exception: Line number = 49 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 39 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15

y esta salida de depuración de VS:

arg = 0 case 0 System.Exception: Line number = 37 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 42 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15 arg = 1 case 1 System.Exception: Line number = 43 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 48 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15 arg = 2 case default System.Exception: Line number = 49 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 51 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15

Y esta salida desde la línea de comando:

arg = 0 case 0 System.Exception: Line number = 37 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 42 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15 arg = 1 case 1 System.Exception: Line number = 43 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 48 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15 arg = 2 case default System.Exception: Line number = 49 bij linenumbertest.Test.ThrowSomeException(Int32 arg) in c:/Users/nate/Docume nts/Visual Studio 2012/Projects/linenumbertest/Program.cs:regel 51 bij linenumbertest.Program.Main() in c:/Users/nate/Documents/Visual Studio 20 12/Projects/linenumbertest/Program.cs:regel 15

He notado un comportamiento extraño con el número de línea en el seguimiento de la pila de una excepción si la excepción se produce dentro de una instrucción switch .

Aquí hay un ejemplo (el formato importa, por supuesto, debido a los números de línea):

using System; class Program { static void Main(string[] args) { for (int i = 0; i < 3; i++) { try { ThrowSomeException(i); } catch (Exception exc) { Console.WriteLine(exc); } } } private static void ThrowSomeException(int arg) { Console.WriteLine("arg = {0}", arg); switch (arg) { case 0: throw new Exception("Line number = 16"); case 1: throw new Exception("Line number = 18"); default: throw new Exception("Line number = 20"); } } }

La línea informada en el seguimiento de la pila es la línea de la siguiente excepción en la instrucción switch. El programa anterior produce este resultado (tenga en cuenta la discrepancia entre el número de línea en el texto de excepción y el número de línea en el seguimiento de pila):

arg = 0 System.Exception: Line number = 16 at Program.ThrowSomeException(Int32 arg) in x:/test/Program.cs:line 18 at Program.Main(String[] args) in x:/test/Program.cs:line 6 arg = 1 System.Exception: Line number = 18 at Program.ThrowSomeException(Int32 arg) in x:/test/Program.cs:line 20 at Program.Main(String[] args) in x:/test/Program.cs:line 6 arg = 2 System.Exception: Line number = 20 at Program.ThrowSomeException(Int32 arg) in x:/test/Program.cs:line 20 at Program.Main(String[] args) in x:/test/Program.cs:line 6

¿Por qué está pasando esto?

Nota: probé esto con VS 2012 y 2013, compilando tanto en .NET 3.5 como en 4.5 y obtuve los mismos resultados.

Debug vs Release : sorprendentemente, estoy obteniendo este extraño comportamiento solo en Debug, en Release los números de línea son correctos.