Я видел, как люди говорили, что использовать catch без аргументов - плохая форма, особенно если эта catch ничего не делает:
StreamReader reader=new StreamReader("myfile.txt");
try
{
int i = 5 / 0;
}
catch // No args, so it will catch any exception
{}
reader.Close();
Тем не менее, это считается хорошей формой:
StreamReader reader=new StreamReader("myfile.txt");
try
{
int i = 5 / 0;
}
finally // Will execute despite any exception
{
reader.Close();
}
Насколько я могу судить, единственное различие между помещением кода очистки в блок finally и размещением кода очистки после блоков try..catch состоит в том, что в вашем блоке try есть операторы возврата (в этом случае код очистки в finally будет запустить, но кода после попытки .. поймать не буду).
Иначе, что такого особенного в конце концов?
Ответы:
Большая разница в том, что
try...catch
проглотит исключение, скрывая тот факт, что произошла ошибка.try..finally
запустит ваш код очистки, а затем исключение будет продолжаться, чтобы обрабатываться чем-то, что знает, что с ним делать.источник
«Наконец» - это утверждение «Что-то, что вы всегда должны делать, чтобы убедиться, что состояние программы нормальное». Поэтому всегда полезно иметь его, если есть вероятность, что исключения могут отбросить состояние программы. Компилятор также делает все возможное, чтобы обеспечить выполнение вашего кода finally.
«Поймать» - это утверждение «Я могу оправиться от этого исключения». Вы должны восстанавливаться только после исключений, которые вы действительно можете исправить - catch без аргументов говорит: «Эй, я могу восстановиться после чего угодно!», Что почти всегда неверно.
Если бы можно было оправиться от каждого исключения, то это было бы действительно семантическим спором о том, что вы заявляете о своем намерении. Однако это не так, и почти наверняка кадры выше ваших будут лучше оснащены для обработки определенных исключений. Поэтому, наконец, используйте, чтобы ваш код очистки запускался бесплатно, но все же пусть более опытные обработчики справятся с этой проблемой.
источник
Потому что, когда эта единственная строка вызывает исключение, вы об этом не узнаете.
С первым блоком кода исключение будет просто поглощено , программа продолжит выполнение, даже если состояние программы может быть неправильным.
Во втором блоке, исключение будет брошено и пузыри вверх , но
reader.Close()
по - прежнему гарантированно работать.Если исключение не ожидается, не устанавливайте блок try..catch просто так, позже будет сложно отлаживать, когда программа перешла в плохое состояние, и у вас нет идеи, почему.
источник
Наконец выполняется ни на что. Таким образом, если ваш блок try был успешным, он выполнится, если ваш блок try завершится неудачей, он затем выполнит блок catch, а затем блок finally.
Кроме того, лучше попробовать использовать следующую конструкцию:
Поскольку оператор using автоматически переносится в try / finally, поток автоматически закрывается. (Вам нужно будет поставить try / catch вокруг оператора using, если вы хотите перехватить исключение).
источник
Хотя следующие 2 кодовых блока эквивалентны, они не равны.
наконец, блоки особенные. CLR распознает и обрабатывает код внутри блока finally отдельно от блоков catch, а CLR делает все возможное, чтобы гарантировать, что блок finally всегда будет выполняться. Это не просто синтаксический сахар от компилятора.
источник
Я согласен с тем, что кажется консенсусом - пустой «улов» плох, потому что он маскирует любое исключение, которое могло произойти в блоке try.
Кроме того, с точки зрения читабельности, когда я вижу блок try, я предполагаю, что будет соответствующий оператор catch. Если вы используете «try» только для того, чтобы убедиться, что ресурсы выделены в блоке «finally», вместо этого вы можете рассмотреть выражение «using» :
Вы можете использовать оператор using с любым объектом, который реализует IDisposable. Метод dispose () объекта вызывается автоматически в конце блока.
источник
Используйте
Try..Catch..Finally
, если ваш метод знает, как обрабатывать исключение локально. Исключение возникает в Try, Handled in Catch и после этого выполняется очистка в Окончании.В случае, если ваш метод не знает, как обрабатывать исключение, но нуждается в очистке, как только это произошло, используйте
Try..Finally
Таким образом, исключение распространяется на вызывающие методы и обрабатывается, если в вызывающих методах есть какие-либо подходящие операторы Catch. Если в текущем методе или каком-либо из вызывающих методов нет обработчиков исключений, происходит сбой приложения.
Тем
Try..Finally
самым гарантируется, что локальная очистка выполняется перед распространением исключения на вызывающие методы.источник
Блок try..finally будет по-прежнему генерировать любые исключительные ситуации. Все, что
finally
нужно сделать, это убедиться, что код очистки запускается до того, как сгенерировано исключение.Try..catch с пустым catch полностью поглотит любое исключение и скроет тот факт, что это произошло. Читатель будет закрыт, но никто не скажет, произошла ли правильная вещь. Что, если вы намеревались записать i в файл? В этом случае вы не попадете в эту часть кода, а myfile.txt будет пустым. Все ли последующие методы обрабатывают это правильно? Когда вы увидите пустой файл, сможете ли вы правильно угадать, что он пустой, потому что было сгенерировано исключение? Лучше бросить исключение и дать понять, что вы делаете что-то не так.
Другая причина заключается в том, что try..catch сделано так, что это совершенно неправильно. Делая это, вы говорите: «Что бы ни случилось, я справлюсь». Как насчет
StackOverflowException
, вы можете убрать после этого? Как насчетOutOfMemoryException
? В общем, вы должны обрабатывать только те исключения, которые ожидаете и знаете, как их обрабатывать.источник
Если вы не знаете, какой тип исключения перехватить или что с ним делать, нет смысла использовать оператор catch. Вы должны просто оставить это для звонящего по телефону выше, который может иметь больше информации о ситуации, чтобы знать, что делать.
У вас все еще должен быть оператор finally в случае возникновения исключения, чтобы вы могли очистить ресурсы до того, как это исключение будет выдано вызывающей стороне.
источник
С точки зрения читабельности, это более явно говорит будущим читателям кода: «этот материал здесь важен, его нужно делать независимо от того, что происходит». Это хорошо.
Кроме того, пустые операторы catch имеют тенденцию иметь определенный «запах» для них. Они могут быть признаком того, что разработчики не продумывают различные возможные исключения и способы их обработки.
источник
Наконец, необязательно - нет причины иметь блок «Наконец», если нет ресурсов для очистки.
источник
Взяты из: здесь
Возбуждение и отлов исключений не должны происходить регулярно как часть успешного выполнения метода. При разработке библиотек классов клиентскому коду должна быть предоставлена возможность проверить состояние ошибки перед выполнением операции, которая может привести к возникновению исключения. Например, System.IO.FileStream предоставляет свойство CanRead, которое можно проверить перед вызовом метода Read, предотвращая возникновение потенциального исключения, как показано в следующем фрагменте кода:
Dim str As Stream = GetStream () If (str.CanRead) Then 'код для чтения потока End If
Решение о том, проверять ли состояние объекта перед вызовом конкретного метода, который может вызвать исключение, зависит от ожидаемого состояния объекта. Если объект FileStream создается с использованием существующего пути к файлу и конструктора, который должен возвращать файл в режиме чтения, проверка свойства CanRead не требуется; невозможность чтения FileStream будет нарушением ожидаемого поведения вызовов методов, и должно возникнуть исключение. Напротив, если метод задокументирован как возвращающий ссылку FileStream, которая может или не может быть читаемой, рекомендуется проверить свойство CanRead перед попыткой чтения данных.
Чтобы проиллюстрировать влияние на производительность, которое может вызвать использование метода кодирования «выполнение до исключения», производительность приведения, который выдает InvalidCastException в случае сбоя приведения, сравнивается с оператором C # as, который возвращает нули в случае сбоя приведения. Выполнение этих двух приемов одинаково для случая, когда приведение является действительным (см. Тест 8.05), но для случая, когда приведение является недействительным, и использование преобразования приводит к исключению, использование преобразования в 600 раз медленнее, чем использование как оператор (см. тест 8.06). Высокопроизводительное влияние метода выброса исключений включает в себя стоимость выделения, выброса и перехвата исключения, а также стоимость последующей сборки мусора объекта исключения, что означает, что мгновенное воздействие выброса исключения не столь велико. Чем больше исключений,
источник
Неправильно добавлять предложение catch только для того, чтобы отбросить исключение.
источник
Если вы прочитаете C # для программистов, то поймете, что блок finally был разработан для оптимизации приложения и предотвращения утечки памяти.
Например, когда вы открываете соединение с файлом или базой данных, ваш компьютер будет выделять память для обслуживания этой транзакции, и эта память будет сохраняться только после выполнения команды disposed или close. но если во время транзакции произошла ошибка, исходящая команда будет прервана, если только она не была внутри
try.. finally..
блока.catch
отличался отfinally
того, что catch был спроектирован, чтобы дать вам возможность обрабатывать / обрабатывать или интерпретировать ошибку самостоятельно. Думайте об этом как о человеке, который говорит вам: "Эй, я поймал некоторых плохих парней, что ты хочешь, чтобы я сделал с ними?" В то время какfinally
был разработан, чтобы убедиться, что ваши ресурсы были правильно размещены. Подумайте о ком-то, что, есть ли плохие парни, он позаботится о том, чтобы ваша собственность была в безопасности.И вы должны позволить этим двум работать вместе навсегда.
например:
источник
Наконец, вы можете очистить ресурсы, даже если ваш оператор catch выбрасывает исключение в вызывающую программу. В вашем примере, содержащем пустое выражение catch, разница невелика. Однако, если вы поймете, что вы выполняете некоторую обработку и выкидываете ошибку, или даже просто не получаете ее вообще, то, наконец, все равно запускается.
источник
Ну, во-первых, плохая практика - ловить исключения, с которыми вы не справляетесь. Прочтите главу 5 о производительности .Net с точки зрения повышения производительности и масштабируемости приложений .NET . Заметьте, что вы, вероятно, должны загружать поток внутри блока try, таким образом, вы можете перехватить соответствующее исключение в случае сбоя. Создание потока вне блока try отменяет его назначение.
источник
Среди многих причин, исключения очень медленно выполняются. Вы можете легко нанести вред вашему времени выполнения, если это часто случается.
источник
Проблема с блоками try / catch, которые перехватывают все исключения, состоит в том, что ваша программа теперь находится в неопределенном состоянии, если происходит неизвестное исключение. Это полностью противоречит правилу быстрого отказа - вы не хотите, чтобы ваша программа продолжала работу в случае возникновения исключения. Вышеупомянутый try / catch даже перехватит OutOfMemoryExceptions, но это определенно то состояние, в котором ваша программа не будет работать.
Блоки try / finally позволяют выполнить очистку кода, но при этом быстро завершаются неудачно. В большинстве случаев вам нужно только перехватить все исключения на глобальном уровне, чтобы их можно было зарегистрировать, а затем выйти.
источник
Эффективная разница между вашими примерами незначительна, если не выдается никаких исключений.
Однако, если исключение выдается в предложении try, первый пример полностью его проглотит. Второй пример поднимет исключение до следующего шага вверх по стеку вызовов, поэтому разница в указанных примерах заключается в том, что один полностью скрывает любые исключения (первый пример), а другой (второй пример) сохраняет информацию об исключениях для возможной последующей обработки, в то время как по-прежнему выполняем контент в предложении 'finally'.
Например, если вы поместите код в предложение 'catch' в первом примере, который вызвал исключение (либо то, которое было инициировано, либо новое), код очистки считывателя никогда не будет выполнен. Наконец, выполняется независимо от того, что происходит в предложении catch.
Таким образом, основное различие между «catch» и «finally» заключается в том, что можно рассмотреть содержимое блока «finally» (за редкими исключениями). гарантированно выполненным даже в случае непредвиденного исключения, тогда как любой код, следующий за Предложение «catch» (но за исключением предложения «finally») не несет такой гарантии.
Кстати, Stream и StreamReader реализуют IDisposable и могут быть заключены в блок «using». Блоки 'Using' являются семантическим эквивалентом try / finally (без 'catch'), поэтому ваш пример можно выразить более кратко в виде:
... который закроет и удалит экземпляр StreamReader, когда он выйдет из области видимости. Надеюсь это поможет.
источник
try {…} catch {} не всегда плохо. Это не обычный шаблон, но я склонен использовать его, когда мне нужно отключить ресурсы, несмотря ни на что, например, закрыть (возможно) открытые сокеты в конце потока.
источник