Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
 Аватар для Enifan
1848 / 1190 / 501
Регистрация: 14.10.2018
Сообщений: 3,211

Выйти из метода и вернуть -1, находясь внутри рекурсивной локальной функции

14.03.2020, 12:49. Показов 3513. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть метод, внутри него рекурсивная локальная функция (это условие является важным и изменению не подлежит). Суть в чем, если внутри рекурсивной локальной функции срабатывает определенное условие - выйти из всего метода и вернуть -1, при этом все остальные подсчеты нам уже не важны. Пример ниже - только образец, в реальном примере логика куда больше и сложнее
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
    static int Method(int number)
    {
        return Foo(number);
 
        int Foo(int num)
        {
            if (num == 5)
            {
                // выход из метода Method, вернув -1
            }
            return num == 10 ? num : Foo(num + 2);
        }
    }
Способы решения
1) завести булеву переменную, и при условии num == 5 задать ей например false, и при каждом входе в локальную функцию делать проверку, если не соответствует - сразу делать выход, в методе делать аналогичную проверку. Способ рабочий, но в реальном примере может быть более 1000 вызовов локальной функции, и ждать пока все это закроется - так себе вариант
2) оператор goto. Хорошо подходит для выхода из глубоко-вложенных циклов, но вот за пределы локальной функции он выйти не сможет. Может все же есть лазейка? На данный момент способ не рабочий
3) бросок исключения. Если сработает исключение деления на ноль или выход за пределы массива - пусть срабатывает, я должен себя проверить на правильность написания логики. Если и бросать исключение - то только такое, которого нет в списке, сделанном по умолчанию. В данной теме не силен, возможно все куда проще

Может есть еще более простые варианты ?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.03.2020, 12:49
Ответы с готовыми решениями:

Вернуть значение рекурсивной функции
Доброго времени суток! function calc($a,$b){ if ($a==0){ echo "inkrement<br>"; $res = $res + 1; } else{ for...

Вернуть массив строк и ещё одну переменную из рекурсивной функции
Всем привет.Никак не могу придумать как вернуть массив строк и ещё одну переменную типа int из рекурсивной функции. char...

Нужна помощь с написании рекурсивной функции метода пузырька
Добрый день! Нужна помощь с написании рекурсивной функции метода пузырька. Жутко туплю... #include <iostream> ...

10
 Аватар для Bampo
114 / 82 / 37
Регистрация: 15.02.2020
Сообщений: 206
14.03.2020, 14:21
Enifan, каждый вызов функции увеличивает стек вызовов. Чтобы попасть в начальную точку, в C# придется размотать стек обратно, а это делается только через return. Знаю только один способ одним махом перепрыгнуть в исходную точку - через перехват исключения. Это распространенный паттерн через CancellationToken и OperationCanceledException
1
 Аватар для Enifan
1848 / 1190 / 501
Регистрация: 14.10.2018
Сообщений: 3,211
14.03.2020, 18:34  [ТС]
Цитата Сообщение от Bampo Посмотреть сообщение
через CancellationToken и OperationCanceledException
Примерную суть понял, но вот реализовать в коде не получается. Не могу понять как вызвать данное исключение через токены. Напрямую то можно вызвать (хотя таким образом можно вызвать любое рандомное исключение)
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    static int Method(int number)
    {
        try
        {
            return Foo(number);
        }
        catch (OperationCanceledException)
        {
            return -1;
        }
 
        int Foo(int num)
        {
            if (num == 5)
            {
                // выход из метода Method, вернув -1
                throw new OperationCanceledException();
            }
            return num == 10 ? num : Foo(num + 2);
        }
    }
0
 Аватар для Bampo
114 / 82 / 37
Регистрация: 15.02.2020
Сообщений: 206
14.03.2020, 19:36
Лучший ответ Сообщение было отмечено Enifan как решение

Решение

Enifan, я сперва немного недопонял ситуацию.
Тебе просто нужно изнутри рекурсии бросить исключение OperationCanceledException, т.к. оно наиболее подходит по смыслу.
CancellationToken используется когда нужно завершить асинхронную операцию или когда она просто идет в другом потоке.

Собственный CancellationToken создается из объекта
C#
1
2
cts = new CancellationTokenSource(); 
cancellationToken = cts.Token;
Тогда если операция принимает CancellationToken, то в нужный момент можно вызвать cts.Cancel() и она завершится. Если сам реализуешь такую операцию, то в разных циклах ставишь условие
C#
1
 if (cancellationToken.IsCancellationRequested) throw new OperationCanceledException()
1
 Аватар для Enifan
1848 / 1190 / 501
Регистрация: 14.10.2018
Сообщений: 3,211
14.03.2020, 20:12  [ТС]
Цитата Сообщение от Bampo Посмотреть сообщение
Тебе просто нужно изнутри рекурсии бросить исключение OperationCanceledException, т.к. оно наиболее подходит по смыслу.
Может я не правильно мыслю, но допустим у меня в рекурсии не происходит никакого деления. Я могу быть точно уверен, что бросив исключение DivideByZeroException и поймав его, я смогу выйти из рекурсии и вернуть -1, и казалось бы задача решена, но это не совсем правильно. А может быть позже мне придется переделать логику и потом использовать деление и данное исключение мне может насолить.
Вопрос про OperationCanceledException. Я могу быть уверен в том, что данное исключение не вызовется при обстоятельствах, когда я напишу неверную логику?
PS потоки не использую, если интересно - полный код тут Подсчёт способов раскрасить бинарное дерево, 130 строка кода
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
14.03.2020, 20:16
Цитата Сообщение от Enifan Посмотреть сообщение
Может есть еще более простые варианты ?
А чем обычный return -1 не устраивает?
Стек так и так придется отматывать, что с исключением, что без.
Только с исключением это все будет делаться дольше, да и в принципе использовать исключение в роли ветвления — как-то глупо.
1
 Аватар для Enifan
1848 / 1190 / 501
Регистрация: 14.10.2018
Сообщений: 3,211
14.03.2020, 20:20  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
А чем обычный return -1 не устраивает?
вопрос в том, как мне вернуть -1 из метода, находясь внутри локальной функции
Цитата Сообщение от kolorotur Посмотреть сообщение
Стек так и так придется отматывать, что с исключением, что без.
разве исключение не прерывает все рекурсии ?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
14.03.2020, 22:56
Лучший ответ Сообщение было отмечено Enifan как решение

Решение

Enifan, ну вы же возвращаете результат вложенной функции - вот и вернется -1.
Исключение прерывает рекурсии, но стек вс ем равно отматывается, т.к. рантайму в каждой точке рекурсивного вызова нужно знать - ловится ли тут исключение.
Только времени это больше занимает
1
 Аватар для Enifan
1848 / 1190 / 501
Регистрация: 14.10.2018
Сообщений: 3,211
14.03.2020, 23:02  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
возвращаете результат вложенной функции
в данном примере да, но может быть более сложная логика. Например когда перебираем бинарник, и так идет возврат return Foo() + Foo();. Тут уже такое не прокатит. А вообще мне это нужно было для одного примера, можете посмотреть на ссылку из 5 поста. Так там вообще тип void у локальной функции. И как быть в данном примере ?
Просто меня интересует универсальный вариант выхода. В идеале как если бы отработал goto
0
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
14.03.2020, 23:33
Цитата Сообщение от Enifan Посмотреть сообщение
Просто меня интересует универсальный вариант выхода.
Только используя исключение.
1
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
15.03.2020, 01:51
Цитата Сообщение от Enifan Посмотреть сообщение
Например когда перебираем бинарник, и так идет возврат return Foo() + Foo();.
Ну разбейте на три строчки, делов-то:
C#
1
2
3
4
5
6
7
var foo1 = Foo();
if (foo1 == -1) return -1;
 
var foo2 = Foo();
if (foo2 == -1) return -1;
 
return foo1 + foo2;
Ну или какая у вас там логика возврата.

Цитата Сообщение от Enifan Посмотреть сообщение
Так там вообще тип void у локальной функции. И как быть в данном примере ?
Делайте возврат через обычный return.
Если нужно проверять, нормально ли отработала локальная функция или закончилась преждевременно, то измените ее тип с void на bool — на то она и локальная, чтобы ее реализация подгонялась под нужды.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.03.2020, 01:51
Помогаю со студенческими работами здесь

Вернуть значение локальной переменной анонимной функции
Как получить значение x, не делая его глобальной переменной (не менять место его объявления) ? elem.onclick = function() { var...

Динамическое выделение памяти внутри функции (что вернуть из функции, если не удалось выделить память?)
такое дело, есть функция, которая выполняет некоторую операцию, функция при успешном выполнении должна вернуть 0, при ниудачном код...

Вызов функции внутри другой функции с передачей локальной переменной по ссылке
Столкнулся с очень с интересной проблемой. Можно ли так делать? #include <iostream> using std::cout; void f(const int...

Разработать программу по алгоритму с использование рекурсивной функции и без использования рекурсивной функции
Разработать программу по алгоритму с использование рекурсивной функции и без использования рекурсивной функции.

Как правильно вернуть true внутри функции
Доброго времени суток! У меня возникла проблема при валидации данных отправляемых формой авторизации пользователя! Скрипт: var...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Символьное дифференцирование
igorrr37 13.02.2026
/ * Программа принимает математическое выражение в виде строки и выдаёт его производную в виде строки и вычисляет значение производной при заданном х Логарифм записывается как: (x-2)log(x^2+2) -. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru