Несколько операций в блоке finally - PullRequest
2 голосов
/ 21 февраля 2009

Допустим, вы очистили какой-то ресурс, например: Это C #.

try{/*stuff*/}
catch(Exception e) {/*rollback logs etc.*/}
finally{
 if( context.Transaction != null )
  context.Transaction.Dispose();
 context.Connection.Close();
 context.Connection.Dispose();
}

Было бы лучше сделать это вместо этого?

try{/*stuff*/}
catch(Exception e) {/*rollback logs etc.*/}
finally{
 try{
  if( context.Transaction != null )
   context.Transaction.Dispose();
 }catch(Exception e){/*logs*/}
 finally{
  context.Connection.Close();
  context.Connection.Dispose();
 }
}

Таким образом, если транзакция.dispose завершится неудачно, соединение получит возможность закрыть.

Ответы [ 4 ]

12 голосов
/ 21 февраля 2009

Было бы лучше сделать это вместо этого?

Вы бы лучше с несколькими использованием блоков.

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

Но лучше:

using (var resA = GetMeAResourceNeedingCleanUp())
using (var resB = new AnotherResourceNeedingCleanUpn(...)) {
  // Code that might throw goes in here.
}

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

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

Обратите внимание, что "Руководство по разработке структуры" (2 и ed) имеет это как (§9.4.1):

AVOID выдает исключение изнутри Dispose (bool) за исключением критических ситуации, когда содержащий процесс был поврежден (утечки, противоречивые общее состояние и т. д.).

3 голосов
/ 21 февраля 2009

Три очка:

  • Вам не нужно звонить Close, а также распоряжаться
  • Распределение транзакции в отдельном блоке finally является лучшей идеей, поскольку она защищает от исключений, возникающих при удалении. (Это не должно случаться часто, но может случиться.)
  • Оператор using почти всегда является самым чистым способом распоряжаться ресурсами. Я использую это, даже если я также хочу блок try / catch, просто потому что это идиоматический способ сказать: «Это использует ресурс, который я хочу разместить в конце блока» *

Их объединение приведет к двум операторам использования:

using (SqlConnection conn = ...)
{
    using (Transaction trans = ...)
    {
    }
}

Если вы хотите избежать чрезмерного отступа, вы можете написать это как:

using (SqlConnection conn = ...)
using (Transaction trans = ...)
{
}
0 голосов
/ 21 февраля 2009

Мне не нравятся мои предложения finally, чтобы они были слишком многословными (или какими-либо другими словами). Я бы реорганизовал очистку вашего ресурса в некоторый служебный класс. Сохраните все вложенные условия try и «if null», чтобы вам было удобнее использовать повторно. Например, поскольку ваша логика очистки находится только в одном месте, вы можете легко передумать позже о том, действительно ли вам нужно вызывать Dispose ().

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

try{/*stuff*/}
catch(Exception e) {/*rollback logs etc.*/}
finally{
  Utility.cleanup(context);
}
0 голосов
/ 21 февраля 2009

почему вызов Dispose завершится неудачно? Вы также можете быть слишком осторожны в какой-то момент. Как обернуть каждый «новый» оператор try / catch на случай, если память исчерпается ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...