В .NET есть ли какое-либо преимущество в try / catch, где catch просто перестраивает [дубликат]

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

  •  05-07-2019
  •  | 
  •  

Вопрос

Возможный Дубликат:
Зачем перехватывать и повторно отбрасывать исключение в C #?

Иногда я сталкиваюсь с кодом на C #, который выглядит примерно так:

        try
        {
            // Some stuff
        }
        catch (Exception e)
        {
            throw e;
        }

Я понимаю, что можно сделать что-то вроде регистрации сообщения об исключении, а затем повторно скопировать его.Я говорю о уловке, которая только перепрофилирует исключение.Я не вижу в этом смысла.У меня есть три вопроса:

1) Есть ли в этом какое-то преимущество

2) Замедляет ли это работу кода вообще

3) Имело бы ли это какое-либо значение, если бы блок catch был следующим:

        catch (Exception)
        {
            throw;
        }
Это было полезно?

Решение

Это перебрасывает точное то же исключение:

    catch (Exception)
    {
        throw;
    }

Тогда как это перебрасывает исключение без исходной трассировки стека:

    catch (Exception e)
    {
        throw e;
    }

Часто есть веская причина для throw; , так как вы можете записать в журнал исключение или сделать другие действия перед тем, как выбросить исключение. Я не знаю каких-либо веских причин для throw e; , поскольку вы уничтожите ценную информацию о трассировке стека.

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

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

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

Основное отличие состоит в том, что трассировка стека исключения будет изменена, чтобы показать, что она возникла из местоположения try-catch в первом примере.

Второй пример поддерживает трассировку стека.

Есть ли преимущество

Вообще говоря, нет. Все, что будет делать этот паттерн - это сброс трассировки стека до точки нового броска. Это только усложнит для разработчиков поиск источника проблемы

Замедляет ли он вообще код

Вообще? Возможно. Замедлить его какой-нибудь ощутимой разницей? №

Будет ли какая-то разница, если блок catch будет следующим?

Да, этот улов по сути полностью избыточен. Это отбросит исключение, которое будет поддерживать исходную трассировку стека и не окажет заметного влияния на ваше приложение.

1 - я не вижу никакого преимущества вообще. Если вы не обрабатываете исключение, оставьте попробовать / поймать. Другая проблема в этом примере заключается в том, что вы генерируете не само исключение, а новое.

2 - да - но, если это не находится в большом цикле повторяющегося кода, вы, скорее всего, не заметите разницы.

3 - Да. В первом примере вы работаете со стеком вызовов. В этом примере стек остается нетронутым путем всплытия исключения, а не создания нового.

Если вы действительно ничего не делаете, есть только одно преимущество, которое я когда-либо нашел: вы можете поставить точку останова в строке throw . Это делает его очень конкретным (вместо того, чтобы просто ломаться всякий раз, когда генерируется этот тип исключения).

Я бы сделал это только во время отладки, а затем вернул бы код обратно.

Я написал быстрый тест, чтобы показать различия. Вот код теста:

try
{
    var broken = int.Parse("null");
}
catch (Exception ex1)
{
    System.Diagnostics.Trace.WriteLine(ex1.ToString());
}

try
{
    try
    {
        var broken = int.Parse("null");
    }
    catch (Exception)
    {
        throw;
    }
}
catch (Exception ex2)
{
    System.Diagnostics.Trace.WriteLine(ex2.ToString());
}

try
{
    try
    {
        var broken = int.Parse("null");
    }
    catch (Exception ex3)
    {
        throw ex3;
    }
}
catch (Exception ex4)
{
    System.Diagnostics.Trace.WriteLine(ex4.ToString());
}

Запустив это, я получаю следующий вывод:

A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Int32.Parse(String s)
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 18
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Int32.Parse(String s)
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 33
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 49

Вы заметите, что первые два исключения работают одинаково. Итак, «брось» ничего не меняет, если исключение перемещается вверх по стеку. Однако "throw ex3;" приводит к тому, что сообщаемое исключение будет другим, изменяя трассировку стека для исключения.

Это часто хорошо для регистрации. Кроме того, если вы пропустите аргумент в re-throw, то это не изменит трассировку стека e.

Иногда вы хотите пропустить определенные типы, например, Вот специальная обработка для всего, кроме FooException:

try
{
    // ...
}
catch (FooException)
{
    throw;
}
catch (Exception ex)
{
    // handle differently, like wrap with a FooException
    throw new FooException("I pitty the Foo.", ex);
}

Конечно.

Чаще всего вы хотите зарегистрировать исключение перед его выбросом и, возможно, записать некоторые значения переменных из метода.

Однако, просто поймав его, чтобы бросить, вы мало что получите.

Просто так, нет. Тем не менее, вы можете сделать это:

catch (Exception ex)
{
     LogException(ex);
     throw;
}

Где LogException () - это пользовательский класс, который регистрирует исключение или отправляет уведомление по электронной почте или что-то в этом роде.

Я думаю, смысл в том, чтобы гарантировать, что генерируется только один тип исключения.Это довольно плохой анти-паттерн, ИМХО

например ,

try
{
    throw XYZ();
}
catch(Exception e)
{
    throw e;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top