Подтвердить что ты не робот

Являются ли эти try/catch'es эквивалентными?

Сценарий

У меня есть метод, который выполняет операцию базы данных (скажем). Если во время этой операции возникает какое-либо исключение, я просто хочу передать это исключение вызывающему. Я не хочу выполнять какую-либо конкретную задачу в блоке catch, предполагая, что вызывающий абонент сделает все, что захочет сделать с этим исключением. В этом случае, какая из них является подходящей техникой обработки исключений?

try
{
    // Some work that may generate exception
}
catch(Exception)
{
    throw;
}
finally
{
    // Some final work
}

Является ли вышеупомянутое эквивалентным следующему try/catch/finally?

try
{
    // Some work that may generate exception
}
catch
{
    throw;
}
finally
{
    // Some final work
}

Является ли вышеупомянутое эквивалентным следующему try/finally?

try
{
    // Some work that may generate exception
}
finally
{
    // Some final work
}

Какой из них лучше другого? Какой из них следует использовать?

4b9b3361

Ответ 1

Нет, они не эквивалентны. В некоторых случаях они могут быть эквивалентны, но общий ответ - нет.

Различные типы блоков catch

catch блок с указанным типом исключения

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

try
{
   // Some work that may generate exception
}
catch (Exception)
{
   throw;
}
finally
{
   // Some final work
}

catch блок без указанного типа исключения

Следующий блок catch без спецификатора типа также будет захватывать не управляемые исключения, которые необязательно представлены управляемым объектом System.Exception, а затем выполняет блок finally, который будет происходить независимо от того, является ли исключение был брошен или нет.

try
{
   // Some work that may generate exception
}
catch
{
   throw;
}
finally
{
   // Some final work
}

finally блок без блока catch

Если у вас нет блока catch вообще, ваш finally будет выполняться независимо от того, произошло ли исключение.

try
{
   // Some work that may generate exception
}
finally
{
  // Some final work
}

Когда они эквивалентны?

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

Примечания

Заметка о throw

Следующие два кода содержат тонкую разницу. Последний повторит исключение, что означает, что он перепишет трассировку стека исключений, поэтому они эквивалентны не:

catch (Exception e)
{
    throw;
}

и

catch (Exception e)
{
    throw e;
}

Если вы используете finally с IDisposable, следующие два фрагмента кода почти эквивалентны, но с некоторыми незначительными отличиями:

  • Когда объект имеет значение null, оператор using не даст вам NullReferenceException
  • При использовании метода try - finally переменная остается в области видимости, хотя она очень не рекомендуется использовать любой объект после его удаления. Однако вы все равно можете переназначить переменную на что-то еще.

    Что-то obj = null; пытаться {   obj = new Что-то()   // Сделай что-нибудь } в конце концов {   obj.Dispose(); }

и

using (var obj = new Something())
{
    // Do something
}

Ответ 2

До сих пор у вас есть хорошие ответы, но есть интересная разница, о которой они пока не упоминали. Рассмотрим:

try { ImpersonateAdmin(); DoWork(); } 
finally { RevertImpersonation(); }

против

try { ImpersonateAdmin(); DoWork(); }
catch { RevertImpersonation(); throw; }
finally { RevertImpersonation(); }

Предположим, что DoWork выбрасывает.

Теперь первый вопрос под рукой: "есть ли блок catch, который может обрабатывать это исключение", потому что если ответ "нет", поведение программы определяется реализацией. Среда выполнения может решить немедленно прекратить процесс, может потребоваться запустить блоки finally до того, как она завершит процесс, возможно, он захочет запустить отладчик, сломанный в момент необработанного исключения, он может сделать все, что ему нравится. Программе с необработанными исключениями разрешено что-либо делать.

Таким образом, среда выполнения начинает поиск блока catch. Там нет в этой инструкции try, поэтому он ищет стек вызовов. Предположим, он находит один с фильтром исключений. Он должен знать, разрешит ли фильтр обрабатывать исключение, поэтому фильтр запускается до того, как будет возвращено олицетворение. Если фильтр случайно или намеренно делает то, что может сделать только администратор, это будет успешным! Возможно, это не то, что вы хотите.

Во втором примере catch сразу же получает исключение, возвращает олицетворение, бросает, и теперь среда выполнения начинает искать блок catch для обработки повторного броска. Теперь, если есть фильтр, он запускается после возвращения олицетворения. (И, конечно, наконец, снова возвращается, я полагаю, что возвращение к олицетворению здесь идемпотент.)

Это важное различие между этими двумя фрагментами кода. Если абсолютно абсолютно запрещено, чтобы какой-либо код видел глобальное состояние, которое было испорчено попыткой и убрано окончательно, тогда вам нужно поймать до конца. "Наконец" не означает "немедленно", это означает "в конце концов".

Ответ 3

Оба оператора try / catch эквивалентны тем, что они повторно бросают исходное исключение, которое было обнаружено. Однако пустой catch является более широким (как уже указывал Venemo, поймав неуправляемые исключения). Если вы делаете catch исключение и записываете его в переменную, вы можете использовать его для ведения журнала, или вы можете throw создать новое исключение, передав исходное исключение в качестве аргумента, сделав его "внутреннее исключение" .

finally будет функционировать одинаково независимо.

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

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

Допустимые причины для исключения исключения, которое будет повторно выбрано:

  • throw new Exception("WTF Happened", ex); // Use as inner exception
  • Исключение журнала
  • Используйте блок finally для выполнения некоторого кода очистки