Исключения для контроля потока

Здесь есть интересный пост об этом, в отношении потока управления кросс-приложениями.

Хорошо, недавно я столкнулся с интересной проблемой. Генерация 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

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