C # Нужна ли мне TRY / CATCH для того, чтобы бросить? - PullRequest
9 голосов
/ 11 января 2009

Если все, что я хочу сделать, это выбросить исключение на уровень, когда оно возникает?

private void TryCatch()
{
   try
   {
       foo();
   }
   catch (Exception ex)
   {
       throw;
   }
}

private void NoTryCatch()
{
   foo();
}

Разве эти два метода не одинаковы?

Если в TryCatch возникает исключение, оно вызывает уровень, а если исключение возникает в NoTryCatch, исключение также создается на уровне.

Этот вопрос возник после использования ReSharper и того, что он предложил удалить блок try / catch, поскольку он был избыточным.

Ответы [ 8 ]

19 голосов
/ 11 января 2009

Да, эти методы в значительной степени (*) одинаковы. Разница лишь в том, что в первом легко поставить точку останова. Я всегда соглашался со вторым, если только мне действительно не нужно было прорваться туда и только туда (в отличие от немедленного исключения любых исключений этого типа, что было бы легко). Даже если бы я использовал первое, я бы вернул его во вторую форму, прежде чем фиксировать код.

(*) Могут быть некоторые различия в том, как JIT обрабатывает их. Первый получит больше IL, что повлияет на возможности для встраивания и т. Д.

РЕДАКТИРОВАТЬ: Я не могу удержаться от небольшого микро-бенчмаркинга. Похоже, что try / catch / throw оказывает более негативное влияние на производительность, чем просто отключение встраивания:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

public class Test
{
    const int Iterations = 1000000000;

    static void Main()
    {
        Stopwatch sw;

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            SimpleMethod();
        }
        sw.Stop();
        Console.WriteLine("Simple method: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            NoInlining();
        }
        sw.Stop();
        Console.WriteLine("No inlining: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            TryCatchThrow();
        }
        sw.Stop();
        Console.WriteLine("try/catch/throw: {0}", sw.ElapsedMilliseconds);
    }

    static void SimpleMethod()
    {
        Foo();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static void NoInlining()
    {
    }

    static void TryCatchThrow()
    {
        try
        {
            Foo();
        }
        catch (Exception)
        {
            throw;
        }
    }

    static void Foo() {}
}

Компилировать с /o+ /debug-

Результаты (три запуска):

Простой метод: 504, 495, 489
Нет вставки: 2977, 3060, 3019
попробуй / поймай / брось: 5274, 4543, 5145

3 голосов
/ 11 января 2009

Нет, вам не нужен try catch. Единственная причина, по которой вы захотите использовать первую функцию, заключается в том, что вы хотели бы сделать некоторые записи или освободить ресурсы перед дальнейшей обработкой функции.

1 голос
/ 11 января 2009

Они действительно не одинаковы. Throw сам по себе или throw ex связывается с информацией трассировки стека и может усложнить отладку.

Лучшая причина перехватить исключение - добавить контекст в трассировку стека, например:

try {
  Foo();
}
catch (Exception e) {
  throw new BetterException("I did something slightly silly", e);
}
1 голос
/ 11 января 2009

Что-то, о чем я думал, но я не был уверен на 100%, поэтому я пошел, чтобы проверить. Иногда я был прав.

Очевидно, что если вы повторно сгенерируете исключение, что и делает ваш код, вы можете изменить трассировку стека. Прежде всего, если вы напишите throw ex;, это сбросит трассировку стека. Во-вторых, даже при написании throw; могут также быть случаи, когда информация отсутствует. См. Эту статью и некоторые комментарии пользователей , которые следуют за ней.

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

1 голос
/ 11 января 2009

Эти два метода по сути одинаковы. В этом случае ReSharper был прав с его предложением.

0 голосов
/ 11 января 2009

Если все, что вы делаете, это перебрасываете исключение, вам не нужен блок try / catch. Обычно вы должны ловить исключения только тогда, когда можете их обработать. В противном случае пусть они распространяются вверх.

0 голосов
/ 11 января 2009

Да, блок try catch является избыточным. Стек будет просто разматываться, пока не будет найден try / catch для обработки исключения.

0 голосов
/ 11 января 2009

ReSharper правильно. Если вы на самом деле не собираетесь ловить и делать что-то с исключением, нет смысла включать блок try..catch.

...