Исключения для контроля потока
Здесь есть интересный пост об этом, в отношении потока управления кросс-приложениями.
Хорошо, недавно я столкнулся с интересной проблемой. Генерация n-го значения в потенциально (практически) бесконечной рекурсивной последовательности. Этот конкретный алгоритм будет находиться по меньшей мере в 10-15 ссылках на стопки в той точке, в которой он преуспевает. Моя первая мысль заключалась в том, чтобы бросить SuccessException, который выглядел примерно так (С#):
class SuccessException : Exception
{
public string Value
{ get; set; }
public SuccessException(string value)
: base()
{
Value = value;
}
}
Затем сделайте что-то вроде этого:
try
{
Walk_r(tree);
}
catch (SuccessException ex)
{
result = ex.Value;
}
Затем мои мысли побрели сюда, где я снова и снова слышал, чтобы никогда не использовать Исключения для управления потоком. Есть ли оправдание? И как бы вы структурировали что-то вроде этого, если бы вы его реализовали?
Ответы
Ответ 1
В этом случае я бы посмотрел на ваш метод Walk_r, у вас должно быть что-то, возвращающее значение, бросая исключение, чтобы указать на успех, НЕ является обычной практикой и, как минимум, будет ОЧЕНЬ смущать любого, кто видит код. Не говоря уже об издержках, связанных с исключениями.
Ответ 2
walk_r должен просто вернуть значение при его ударе. Это довольно стандартный пример рекурсии. Единственная потенциальная проблема, которую я вижу, заключается в том, что вы сказали, что она потенциально бесконечна, и ее нужно будет компенсировать в коде walk_r, сохраняя подсчет глубины рекурсии и останавливаясь при некотором максимальном значении.
Исключение действительно делает кодирование очень странным, поскольку вызов метода теперь выдает исключение для возврата значения вместо простого возврата "обычно".
try
{
Walk_r(tree);
}
catch (SuccessException ex)
{
result = ex.Value;
}
становится
result = Walk_r(tree);
Ответ 3
Не очень хорошая идея генерировать исключения как часть алгоритма, особенно в .net. В некоторых языках/платформах исключения довольно эффективны при броске, и обычно они возникают, когда итерируемый становится исчерпанным, например.
Ответ 4
Почему бы просто не вернуть полученное значение? Если он вообще что-то возвращает, предположите, что он успешный. Если ему не удается вернуть значение, значит это означает, что цикл завершился неудачно.
Если вы должны вернуть сбой, тогда я рекомендую вам исключить исключение.
Ответ 5
Проблема с использованием исключений заключается в том, что tey (в большой схеме вещей) очень неэффективны и медленны. Разумеется, было бы легко иметь условие if в рекурсивной функции, чтобы просто возвращать по мере необходимости. Честно говоря, с объемом памяти на современном ПК это маловероятно (хотя и невозможно), что вы получите переполнение стека с небольшим количеством рекурсивных вызовов (< 100).
Если стек является реальной проблемой, тогда может возникнуть необходимость в "креативе" и реализации стратегии поиска с ограниченным доступом, позволяющей функции возвращаться из рекурсии и перезапускать поиск с последней (самой глубокой) node.
Подводя итог: Исключения должны использоваться только в исключительных обстоятельствах, успех вызова функции, который я не считаю квалифицированным как таковой.
Ответ 6
Использование исключений в обычном программном потоке в моей книге - одна из худших практик.
Рассмотрим бедного сока, который охотится за проглоченными исключениями и запускает отладчик, который останавливается всякий раз, когда происходит исключение. Этот чувак теперь злится... и у него есть топор.: P
Ответ 7
Я собираюсь сыграть здесь адвоката дьявола и сказать палку, за исключением того, чтобы указать успех. Это может быть дорого бросить/поймать, но это может быть незначительным по сравнению со стоимостью самого поиска и, возможно, менее запутанным, чем ранний выход из метода.