Сохранение исходной трассировки стека / номеров строк в исключениях .NET

StackOverflow https://stackoverflow.com/questions/1585082

  •  22-09-2019
  •  | 
  •  

Вопрос

Понимание разницы между бросить бывшего и бросок, почему исходная трассировка стека сохранена в этом примере:

    static void Main(string[] args)
    {
        try
        {
            LongFaultyMethod();
        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.StackTrace);
        }
    }

    static void LongFaultyMethod()
    {
        try
        {
            int x = 20;
            SomethingThatThrowsException(x);
        }
        catch (Exception)
        {
            throw;
        }
    }

    static void SomethingThatThrowsException(int x)
    {
        int y = x / (x - x);
    }

Но не в этом случае:

    static void Main(string[] args)
    {
        try
        {
            LongFaultyMethod();
        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.StackTrace);
        }
    }

    static void LongFaultyMethod()
    {
        try
        {
            int x = 20;
            int y = x / (x - 20);
        }
        catch (Exception)
        {
            throw;
        }
    }

Второй сценарий выдает тот же результат, что и бросить бывшего стал бы?

В обоих случаях ожидается увидеть номер строки, в которой инициализируется y.

Это было полезно?

Решение

Я не уверен, относится ли это ограничение к языку C #, CLI или к их реализации Microsoft, но ваш второй пример - это случай, когда явный вызов Exception.InternalPreserveStackTrace требуется, как задокументировано в следующем посте.Поскольку этот метод является internal, как правило, это должно быть вызвано через отражение.Проблемы с производительностью, связанные с этим, могут быть почти полностью устранены путем создания Action<Exception> для вызова, как показано в конце этого ответа.

Ссылка: Повторное перемещение исключений и сохранение полной трассировки стека вызовов

Редактировать: После повторного изучения ECMA-335, Раздел I §12.4.2 (обработка исключений) и Раздел III § 4.24 (повторный ввод), я теперь считаю, что поведение, которое вы видите, является семантической ошибкой в среде CLR (реализация CLI от Microsoft).Единственная конкретная ссылка на поведение - это "A rethrow не изменяет трассировку стека в объекте ". В описанном здесь случае повторное перемещение фактически изменяет трассировку стека, делая PreserveStackTrace найдите обходной путь для устранения ошибки know CLR.

static void LongFaultyMethod() 
{ 
    try 
    { 
        int x = 20; 
        int y = x / (x - 20); 
    } 
    catch (Exception ex) 
    { 
        PreserveStackTrace(ex); // <-- add this line
        throw; 
    } 
} 

PreserveStackTrace вот оптимизация той, что взята из этой записи в блоге:

private static readonly Action<Exception> _internalPreserveStackTrace =
    (Action<Exception>)Delegate.CreateDelegate(
        typeof(Action<Exception>),
        typeof(Exception).GetMethod(
            "InternalPreserveStackTrace",
            BindingFlags.Instance | BindingFlags.NonPublic));

public static void PreserveStackTrace(Exception e)
{
    _internalPreserveStackTrace(e);
}

Другие советы

Потому что во втором примере вы повторно создаете исключение из того же метода.Во-первых, его выбросили из другого метода, вот почему.В области одного метода трассировка стека может быть только одной.

Поступайте следующим образом, лучший способ - это всегда переносить исключение внутрь нового исключения, чтобы вы видели глубину исключения.

"Если повторный ввод был выполнен в тем же методом (трассировка стека исключений содержит только одну информацию о номере строки для каждого метода вы никогда не увидите трассировку стека это в методе A, в строке под номером 2 было сгенерировано исключение, а затем тем же самым Методом A оно было повторно скопировано из строки номер 17, оно будет содержать только последнюю номер строки, из которой было создано исключение повторно скопировано "

try        
{            
   int x = 20;            
   int y = x / (x - 20);        
}        
catch (Exception ex)        
{            
   // do something here.. like log or something
   throw new Exception("Internal Exception", ex);        
}

Я удивлен , что так много комментариев не читают мой комментарий !!Я написал в комментарии, что вам, вероятно, следует безопасно зарегистрировать это, существуют различные причины, если код верхнего уровня поглощает исключение, и вы не знаете, какое и где было сгенерировано исключение, ведение журнала поможет вам пересечь исключение !!!

Если вам не нужно регистрироваться, то не перехватывайте исключение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top