У нас есть OnExceptionAspect PostSharp, применяемый к каждому методу нашего проекта, который искажает номера строк, указанные в трассировке стека: номер строки внутреннего стека больше не указывает на строку, где исключение произошло, но к закрывающей скобке метода, в котором произошло исключение.PostSharp's OnExceptionAspect искажает строки строк трассировки стека
Это, по-видимому, известное ограничение Windows, которое при реорганизации исключения сбрасывает начало трассировки стека (см. Incorrect stacktrace by rethrow).
Вы можете воспроизвести эту проблему с этим кодом (вам нужно PostSharp установлен):
namespace ConsoleApplication1
{
using System;
using PostSharp.Aspects;
public static class Program
{
public static void Main()
{
try
{
Foo(2);
}
catch (Exception exception)
{
var type = exception.GetType();
Console.Write(type.FullName);
Console.Write(" - ");
Console.WriteLine(exception.Message);
Console.WriteLine(exception.StackTrace);
}
}
private static void Foo(int value)
{
if (value % 2 == 0)
{
throw new Exception("Invalid value.");
}
Console.WriteLine("Hello, world.");
}
}
[Serializable]
public class LogExceptionAspect : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs methodExecutionArgs)
{
}
}
}
Выполнение этого кода дает следующую трассировку стека:
System.Exception - Invalid value.
at ConsoleApplication1.Program.Foo(Int32 value) in …\Program.cs:line 36
at ConsoleApplication1.Program.Main() in …\Program.cs:line 15
Line 36 не является throw new Exception("Invalid value.");
, но закрытие скобка private static void Foo(int value)
.
Решение состоит в том, чтобы обернуть исключение в новой и повторно выдать его внутри метода OnException в OnExceptionAspect:
[assembly: ConsoleApplication1.LogExceptionAspect]
namespace ConsoleApplication1
{
using System;
using PostSharp.Aspects;
public static class Program
{
public static void Main()
{
try
{
Foo(2);
}
catch (Exception exception)
{
while (exception != null)
{
var type = exception.GetType();
Console.Write(type.FullName);
Console.Write(" - ");
Console.WriteLine(exception.Message);
Console.WriteLine(exception.StackTrace);
exception = exception.InnerException;
}
}
}
private static void Foo(int value)
{
if (value % 2 == 0)
{
throw new Exception("Invalid value.");
}
Console.WriteLine("Hello, world.");
}
}
[Serializable]
public class LogExceptionAspect : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs methodExecutionArgs)
{
throw new Exception("Foo", methodExecutionArgs.Exception);
}
}
}
Это дает правильные номера строк (throw new Exception("Invalid value.");
является по линии 37 в настоящее время):
System.Exception - Foo
at ConsoleApplication1.LogExceptionAspect.OnException(MethodExecutionArgs methodExecutionArgs) in …\Program.cs:line 49
at ConsoleApplication1.Program.Foo(Int32 value) in …\Program.cs:line 41
at ConsoleApplication1.Program.Main() in …\Program.cs:line 15
System.Exception - Invalid value.
at ConsoleApplication1.Program.Foo(Int32 value) in …\Program.cs:line 37
Однако это решение добавляет мусор следов стеки (System.Exception - Foo
записи не должна действительно существует), и для нас делает их практически бесполезно (помните, что аспект применяются к каждым в нашем проекте: так, если исключение вытесняет двадцать методов, у нас есть двадцать новых вложенных исключений, добавленных в трассировку стека).
Учитывая, что мы не можем - кашляем кашель PHB - избавиться от аспект, какие альтернативы у нас должны иметь правильные номера строк и читаемые следы стека?
postsharp - отличный инструмент. любой, кто использует его, значительно выше уровня PHB – Batavia
@Batavia это не инструмент - это то, как вы его используете. – Albireo