Вариант использования для try-catch-finally и с выгодой и с наконец

Я понимаю, как выгода попытки работает и как попытка наконец работает, но я использую тех, которые (обычно) в двух совершенно других сценариях:

  • попробуйте наконец (или using в C# и VB), главным образом используется вокруг некоторого блока кода среднего размера, который использует некоторый ресурс, который должен быть расположен правильно.
  • выгода попытки главным образом используется также
    • вокруг отдельного оператора, который может перестать работать в очень особенном методе или
    • (как вместилище) на очень высоком уровне приложения, обычно непосредственно ниже некоторого действия пользовательского интерфейса.

По моему опыту, случаи, где try-catch-finally был бы соответствующим, т.е. где блок, в котором я хочу поймать некоторое конкретное исключение, является точно тем же блоком, в котором я использую некоторый доступный ресурс, чрезвычайно редки. Все же разработчики языка C#, VB и Java, кажется, полагают, что это очень общий сценарий; разработчики VB даже думают о добавляющей выгоде к using.

Я пропускаю что-то? Или я просто чрезмерно педантичен со своим строгим использованием выгоды попытки?


Править: Разъясниться: Мой код обычно похож на это (функции, развернутые для ясности):

Try
    do something
    Aquire Resource (e.g. get DB connection)
    Try 
        do something
        Try
            do something that can fail
        Catch SomeException
            handle expected error
        do something else... 
    Finally 
        Close Resource (e.g. close DB connection)
    do something
Catch all
    handle unexpected errors

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

8
задан Heinzi 17 February 2010 в 06:00
поделиться

10 ответов

Цитата из MSDN

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

Чтобы было еще понятнее, представьте себе код, который вы хотите выполнить, в 99% случаев он выполняется отлично, но где-то в куске может возникнуть ошибка, вы не знаете где, а созданные ресурсы стоят дорого.

Чтобы быть уверенным на 100%, что ресурсы будут утилизированы, вы используете блок finally, однако вы хотите точно определить тот 1% случаев, когда произошла ошибка, поэтому вы можете установить логирование в секции catch-ing.

Это очень распространенный сценарий.

Редактирование - практический пример

Здесь есть несколько хороших примеров: SQL-транзакции с классом SqlTransaction. Это всего лишь один из многих способов использования Try, Catch & Finally, и он демонстрирует его очень хорошо, хотя using(var x = new SqlTranscation) может быть эффективным в некоторых случаях.

Так что вот так.

var connection = new SqlConnection();

var command = new SqlCommand();

var transaction = connection.BeginTransaction();

command.Connection = connection;
command.Transaction = transaction;

А вот дальше начинается самое интересное

///
/// Try to drop a database
///
try
{
    connection.Open();

    command.CommandText = "drop database Nothwind";

    command.ExecuteNonQuery();
}

Итак, представим, что вышеописанное по какой-то причине не работает и возникает исключение

///
/// Due to insufficient priviligies we couldn't do it, an exception was thrown
///
catch(Exception ex)
{
    transaction.Rollback();
}

Транзакция будет откачена! Помните, что изменения, внесенные в объекты внутри try/catch, не будут откачены, даже если вы вложите их в using!

///
/// Clean up the resources
///
finally
{

    connection.Close();
    transaction = null;
    command = null;
    connection = null;
}

Теперь ресурсы очищены!

16
ответ дан 3 November 2019 в 12:13
поделиться

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

try {
    // some code
    SomeResource res = new SomeResource();
    try {
        res.use();
    } finally {
        res.close();
    }
    // some more code
} catch( Exception ex ) {
    handleError( ex );
}

Это закрывает ресурс как можно раньше в любом случае (ошибка или нет), но по-прежнему обрабатывает все возможные ошибки при создании или использовании ресурса в одном блоке catch.

3
ответ дан 3 November 2019 в 12:13
поделиться

Не ответ на ваш вопрос, а забавный факт.

Реализация компилятора C # от Microsoft на самом деле не может обрабатывать try-catch-finally. Когда мы анализируем код

try { Foo() } 
catch(Exception e) { Bar(e); }
finally { Blah(); }

, мы фактически делаем вид, что код был написан

try 
{
   try { Foo(); }
   catch(Exception e) { Bar(e); }
}
finally { Blah(); }

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

12
ответ дан 3 November 2019 в 12:13
поделиться

Пример:

Try
   Get DB connection from pool
   Insert value in table
   do something else...
Catch
   I have an error... e.g.: table already contained the row I was adding
   or maybe I couldn't get the Connection at all???
Finally
   if DB connection is not null, close it.

Более "обычного" примера и не придумаешь. Жаль, что некоторые люди все еще забывают поместить закрытое соединение в Finally, где ему и место, а не в блок Try... :(

10
ответ дан 3 November 2019 в 12:13
поделиться

Четыре буквы.

Они функционально идентичны, просто написаны по-разному.

-121--2532265-

Если вы имеете в виду, как снять «проверенное» состояние со всех флажков:

$('input:checkbox').removeAttr('checked');
-121--851558-

Я бы почти всегда использовал try-catch-finaly в случаях, когда вам нужно что-то утилизировать во всех случаях, и вы используете этот случай для регистрации ошибки и/или информирования пользователя.

1
ответ дан 3 November 2019 в 12:13
поделиться

Я часто пишу код, который выглядит примерно так:

Handle h = ...
try {
   // lots of statements that use handle
} catch (SomeException ex) {
   // report exception, wrap it in another one, etc
} catch (SomeOtherException ex) {
   // ...
} finally {
   h.close();
}

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

.
6
ответ дан 3 November 2019 в 12:13
поделиться

Имеется перегрузка группы метод, который принимает IEqualityComparer как параметр, но есть ли эквивалентно использованию предложения group?

Вы всегда можете сгруппировать по анонимному типу, если вам просто нужно быстрое встроенное решение и вы не беспокоитесь о том, чтобы набрать точный тип для ключей:

var grouped =
  from it in items 
  group it by new {it.Coordinate.Latitude, it.Coordinate.Longitude};
-121--2793608-

Если вам не нужно менять Look and Feel, не могли бы вы попробовать поставить UIManager.setLookAndFeel

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

-121--335519-

Другое использование состоит в удалении дескриптора файла во вложении электронной почты при использовании объектов почты System.Web.Mail для отправки электронной почты. Я узнал это, когда мне пришлось программно открыть Crystal Report, сохранить его на диске, прикрепить к электронной почте, а затем удалить с диска. Явный .Dispose () был необходим в Finally, чтобы убедиться, что я могу удалить его, особенно в случае выброшенного исключения.

0
ответ дан 3 November 2019 в 12:13
поделиться

По моему опыту, случаи, когда try-catch-finally были бы уместными, т.е. когда блок, в котором я хочу поймать какое-то конкретное исключение, является точно таким же блоком, в котором Пользуюсь каким-то одноразовым ресурсом, встречаются крайне редко. Тем не менее, разработчики языков C #, VB и Java, похоже, считают это очень распространенным сценарием; дизайнеры VB даже думают о добавлении уловки в using.

вы:

try {
   //use resource
} catch (FirstException e) {
   // dispose resource
   // log first exception
} catch (SecondException e) {
   // dispose resource
   // log first exception
} catch (ThirdException e) {
   // dispose resource
   // log first exception
}

я:

try {
  //use resource
} catch (FirstException e) {
  // log first exception
} catch (SecondException e) {
  // log first exception
} catch (ThirdException e) {
  // log first exception
} finally {
  // dispose resource
}

чувствуете сопротивление?)

-1
ответ дан 3 November 2019 в 12:13
поделиться

Это может облегчить это

using HWND = System.IntPtr;

Затем используйте HWND в своем pInvoke..., чтобы облегчить чтение и сохранить его «таким же», как подпись pinvoke.

Надеюсь, что это поможет, С уважением, Том.

-121--4378620-

Этот код выдаст арифметическое исключение :

int x = 1 / 0;
-121--2843426-

Я думаю, что вы совершенно правы. От. Руководство по проектированию Net Framework , написанное некоторыми ведущими архитекторами Microsoft:

НЕ . Исключения должны часто разрешается распространять вверх стек вызовов.

В хорошо написанном коде попробуйте окончательно [или использование] встречается гораздо чаще, чем попробовать-поймать. Это может показаться сначала контринтуитив, но поймать блоки не нужны в удивительном количество дел. С другой стороны, вы всегда должны учитывать, try-finally [или использование] может быть полезным для очистки.

стр. 230 раздел 7,2

3
ответ дан 3 November 2019 в 12:13
поделиться

Как насчет чего-то вроде:

  Dim mainException as Exception = Nothing

  Try
    ... Start a transaction
    ... confirm the transaction
  Catch Ex as Exception
    mainException = Ex
    Throw
  Finally
    Try
      ... Cleanup, rolling back the transaction if not confirmed
    Catch Ex as Exception
      Throw New RollbackFailureException(mainException, Ex)
    End Try
  End Try

Предположим, что RollbackFailureException включает поле "OriginalException", а также "InnerException", и принимает параметры для обоих. Не хочется скрывать тот факт, что во время отката произошло исключение, но и не хочется терять исходное исключение, которое вызвало откат (и могло бы дать подсказку о том, почему произошел откат).

1
ответ дан 3 November 2019 в 12:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: