Почему я должен выводить блок try / catch из цикла?

#c#

#c#

Вопрос:

Вот руководство по просмотру кода от команды Practice amp; Patterns.http: // msdn.microsoft.com/zh-cn / library/ms998574#scalenetchapt13_topic7 (ссылка автоматически переходит в раздел исключений.)

Они сказали, что вы должны выводить блок try / catch из цикла при обработке исключения, я хочу знать, почему?

Ответ №1:

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

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

Комментарии:

1. 1 Единственный «правильный» ответ, поскольку он относится к блоку try / catch, а не только к исключениям. Однако у меня есть проекты, в которых обработка должна продолжаться, если один из «слушателей» выдает исключение. Мне интересно, как для этого можно выполнить перезапись? например: foreach (var listener in listeners) { try { invoke(Y); } catch (Exception err) { _logger.Warning("Client XX did bla bla", err); }}

2. Это хороший пример: обычно в этой ситуации накладные расходы на try блок незначительны по сравнению со временем, затраченным на invoke() . Однако, если это не так, вы можете использовать вложенный цикл, чтобы избежать перехвата исключений на каждой итерации, что повысит производительность, если большинство вызовов будут invoke() успешными. Что-то вроде int i = 0, len = listeners.length; while (i < len) { try { for (; i < len; i) { invoke(listeners[i]); } } catch (Exception x) { _logger.Warning("Client XX did bla bla", x); i; } } .

3. Хорошее решение. Но, как вы говорите, его следует использовать только в том случае, если было доказано, что это необходимо (путем сравнительного анализа или других мер).

Ответ №2:

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

Если вы поместите блок try / catch за пределы цикла, вам нужно будет обработать только одно исключение.

Комментарии:

1. Я думаю, что цикл будет прерван, если будет создано исключение. Поэтому, независимо от того, помещается ли try / catch в цикл или нет, исключение будет выдано только один раз. Это правильно?

2. @Domi.Zhang — Нет, если вы обработаете исключение в своем catch , цикл возобновится.

Ответ №3:

A try/catch внутри цикла ведет себя иначе, чем вне цикла, если только он не всегда перестраивает исключение.

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

Я думаю, что причина рекомендации заключается в том, что try/catch внутри цикла подозрительно похоже на использование исключений для потока управления. Это указывает на потенциальный «запах кода», а не на жесткое и быстрое правило.

Но разумно игнорировать рекомендацию, если это то, что диктуют ваши требования. Чтобы взять простой, но устаревший пример, в мире без Int32.TryParse (.NET 1.x был не так давно!), Было бы разумно иметь цикл, который анализирует список строк в целые числа, используя Int32.Parse в try / catch внутри цикла.

Комментарии:

1. Блоки Try — это операторы управления потоком, нравится это людям или нет. Либо снаружи, либо внутри цикла, блок try будет управлять потоком, если возникает исключение.


Ответ №4:

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

Если внутри обнаружена ошибка, то обработка вне цикла имеет больше смысла.

Комментарии:

1. Это, безусловно, вызывает накладные расходы; но, не видя кода, невозможно сказать, нужны ли накладные расходы.