Бросить; говорят, что это не reset трассировка стека, но это происходит в определенных обстоятельствах
Возможный дубликат:
неверный stacktrace by rethrow
Общепризнано, что в .NET throw;
не reset выполняется трассировка стека, а throw ex;
.
Однако в этой простой программе я получаю разные номера строк:
void Main()
{
try
{
try
{
Wrapper(); // line 13
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
throw; // line 18
}
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
}
public void Wrapper()
{
Throw(); // line 28
}
public void Throw()
{
var x = (string)(object)1; // line 33
}
Вывод:
System.InvalidCastException: Невозможно наложить объект типа "System.Int32" на тип "System.String". в ConsoleApplication2.Program.Main(String [] args) в C:\long-path\Program.cs: строка 13
System.InvalidCastException: Невозможно наложить объект типа "System.Int32" на тип "System.String". в ConsoleApplication2.Program.Main(String [] args) в C:\long-path\Program.cs: строка 18
Примечание. Первая трассировка стека содержит строку 13, вторая содержит строку 18. Кроме того, ни одна строка 13, ни строка 18 не являются строками, в которых фактически происходит аккомпанемент.
Теперь мой вопрос: в каких обстоятельствах throw;
меняет трассировку стека и в каких обстоятельствах она не меняет трассировку стека?
Обратите внимание, что это уже было замечено, но не ответил в целом.
UPDATE:
Я запустил код выше в режиме отладки, и он дает следующее:
System.InvalidCastException: Невозможно наложить объект типа "System.Int32" на тип "System.String". в ConsoleApplication2.Program.Throw() в C:\long-path\Program.cs: строка 33 в ConsoleApplication2.Program.Wrapper() в C:\long-path\Program.cs: строка 28 в ConsoleApplication2.Program.Main(String [] args) в C:\long-path\Program.cs: строка 13
System.InvalidCastException: Невозможно наложить объект типа "System.Int32" на тип "System.String". в ConsoleApplication2.Program.Throw() в C:\long-path\Program.cs: строка 33 в ConsoleApplication2.Program.Wrapper() в C:\long-path\Program.cs: строка 28 в ConsoleApplication2.Program.Main(String [] args) в C:\long-path\Program.cs: строка 18
Обратите внимание: последний номер строки все еще изменяется
Ответы
Ответ 1
Поскольку Дарин уже указывает, что уменьшенная трассировка стека обусловлена методом inline. Однако есть и точка ссылки на строку, доступная в трассировке стека, не равная.
Я не знаю объяснений позади этого, но есть способ сохранить всю информацию о стеке при повторном исключении. Вам нужно бросить новое исключение и передать тот, который вы поймаете, как внутреннее исключение. При таком подходе объединенная stacktrace будет содержать точку начала исключения, а также точку, в которой исключение будет восстановлено.
Я говорил об этом и приводил полные примеры по различным способам повторного исключения исключений в следующем сообщении в блоге:
.NET Исключения - выброс ex - это зло, но бросок не является невиновным
Ваш комментарий побудил меня к быстрому исследованию, но лучшее, что я смог найти, это этот комментарий Джонатана де Холлекса в блоге о catch and rethrow:
Он также изменяет номер строки в stacktrace в методе, который rethrows (поскольку rethrow становится сайтом throw в этом методе).
Это можно было бы уточнить дальше, но это указывает на то, что, вероятно, сайт-бросок, который затем будет использоваться для получения информации о линии, отслеживается при каждом методе, а повторный вызов заставляет его переопределяться.
Итак, несмотря на то, что stacktrace сохраняется при использовании throw
вместо throw e
, исходный сайт броска будет потерян, если вы не обернете и не выбросите новое исключение.
<суб > Другие вещи, чтобы попробовать; поскольку SO не разрешает прямые сообщения, а выше комментарий был сделан Peli, вы можете попытаться пометить этот вопрос pex
, чтобы привлечь его внимание и привлечь его к следить за этим комментарием.:)
Суб >
Ответ 2
Причина этого происходит из-за того, что метод работает в режиме Release. Если вы не хотите, чтобы методы Wrapper
и Throw
были встроены в режим Release, вы можете украсить их атрибутом [MethodImpl]
:
[MethodImpl(MethodImplOptions.NoInlining)]
public void Wrapper()
{
Throw();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void Throw()
{
var x = (string)(object)1;
}