Этот код является частью приложения, которое выполняет чтение и запись в базу данных, подключенную к ODBC. Он создает запись в базе данных, а затем проверяет, была ли запись успешно создана, а затем возвращается true
.
Я понимаю поток управления следующим образом:
command.ExecuteNonQuery()
задокументирован для выдачи сообщения, InvalidOperationException
когда «вызов метода недопустим для текущего состояния объекта». Следовательно, если это произойдет, выполнение try
блока остановится, finally
блок будет выполнен, а затем выполнится return false;
внизу.
Однако моя IDE утверждает, что return false;
это недостижимый код. И вроде правда, могу удалить и компилируется без нареканий. Однако мне кажется, что не будет возвращаемого значения для пути кода, в котором выбрасывается упомянутое исключение.
private static bool createRecord(String table,
IDictionary<String,String> data,
System.Data.IDbConnection conn,
OdbcTransaction trans) {
[... some other code ...]
int returnValue = 0;
try {
command.CommandText = sb.ToString();
returnValue = command.ExecuteNonQuery();
return returnValue == 1;
} finally {
command.Dispose();
}
return false;
}
В чем моя ошибка понимания здесь?
источник
Dispose
, а поставитьusing
:using (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }
finally
Блок означает что - то другое , чем вы думаете.Ответы:
Предупреждение компилятора (уровень 2) CS0162
Это просто говорит о том, что компилятор достаточно понимает с помощью статического анализа, что он не может быть достигнут, и полностью исключает его из скомпилированного IL (отсюда ваше предупреждение)
Примечание : вы можете доказать этот факт самому себе, попробовав перейти к недоступному коду с помощью отладчика или используя IL Explorer.
finally
Может работать на Exception , (хотя это в стороне) не меняет тот факт , (в данном случае) , то все равно будет Uncaught исключения . Следовательно, последнийreturn
никогда не попадет в цель.Если вы хотите , чтобы код , чтобы продолжить на последний
return
, единственный вариант, чтобы поймать за исключение ;Если вы этого не сделаете, просто оставьте все как есть и удалите
return
.пример
Процитировать документацию
try-finally (Справочник по C #)
наконец
При использовании всего, что поддерживает
IDisposable
интерфейс (который предназначен для высвобождения неуправляемых ресурсов), вы можете заключить это вusing
оператор. Компилятор сгенерируетtry {} finally {}
и внутренне вызоветDispose()
объектисточник
Неправильно.
finally
не проглатывает исключение. Он соблюдает это, и исключение будет сгенерировано как обычно. Он выполнит код только в finally до завершения блока (с исключением или без).Если вы хотите, чтобы исключение было проглочено, вы должны использовать
catch
блок безthrow
символа.источник
return false
поскольку вместо этого вызовет исключение @EhsanSajjadПредупреждение связано с тем, что вы не использовали,
catch
и ваш метод в основном написан так:Поскольку вы используете
finally
исключительно для утилизации, предпочтительным решением будет использованиеusing
шаблона:Этого достаточно, чтобы гарантировать то, что
Dispose
будет называться. Он гарантированно будет вызываться либо после успешного выполнения блока кода, либо после (до) некоторогоcatch
отказа в стеке вызовов (родительские вызовы не работают, верно?).Если бы дело не в утилизации, тогда
достаточно, так как вам никогда не придется возвращаться
false
в конце метода (в этой строке нет необходимости). Ваш метод либо возвращает результат выполнения команды (true
илиfalse
), либо в противном случае генерирует исключение .Также подумайте о том, чтобы генерировать собственные исключения, обертывая ожидаемые исключения (проверьте конструктор InvalidOperationException ):
Обычно это используется, чтобы сказать вызывающему что-то более значимое (полезное), чем может сказать исключение вложенного вызова.
В большинстве случаев вас не волнуют необработанные исключения. Иногда вам нужно убедиться, что он
finally
вызывается, даже если исключение не обработано. В этом случае вы просто ловите его сами и повторно бросаете (см. Этот ответ ):источник
Похоже, вы ищете что-то вроде этого:
Обратите внимание, что
finally
не проглатывает никаких исключенийисточник
У вас нет
catch
блока, поэтому по-прежнему генерируется исключение, которое блокирует возврат.Это неправильно, потому что будет выполнен блок finally, и тогда возникнет неперехваченное исключение.
finally
блоки используются для очистки, и они не перехватывают исключение. Исключение генерируется перед возвратом, поэтому возврат никогда не будет достигнут, потому что исключение было выброшено раньше.Ваша IDE верна, что она никогда не будет достигнута, потому что будет выброшено исключение. Только
catch
блоки могут перехватывать исключения.Читая документацию ,
Это ясно показывает, что finally не предназначен для перехвата исключения, и вы были бы правы, если бы
catch
передfinally
оператором был пустой оператор.источник
Когда генерируется исключение, стек раскручивается (выполнение переходит из функции) без возврата значения, и любой блок catch в кадрах стека над функцией вместо этого перехватит исключение.
Следовательно,
return false
никогда не будет выполняться.Попробуйте вручную создать исключение, чтобы понять поток управления:
источник
В вашем коде:
Это недостаток вашей логики, потому что
finally
блок не перехватит исключение и никогда не достигнет последнего оператора возврата.источник
Последний оператор
return false
недоступен, потому что в блоке try отсутствуетcatch
часть, которая обрабатывала бы исключение, поэтому исключение повторно генерируется послеfinally
блока, и выполнение никогда не достигает последнего оператора.источник
В вашем коде есть два пути возврата, второй из которых недоступен из-за первого. Последний оператор в вашем
try
блокеreturn returnValue == 1;
обеспечивает нормальный возврат, поэтому вы никогда не сможете достичьreturn false;
конца блока метода.FWIW, порядок выполнения, связанный с
finally
блоком, следующий: сначала будет вычислено выражение, передающее возвращаемое значение в блоке try, затем будет выполнен блок finally, а затем будет возвращено вычисленное значение выражения (внутри блока try).Что касается потока при исключении ... без a
catch
,finally
будет выполняться при исключении до того, как исключение будет повторно выброшено из метода; нет "обратного" пути.источник