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

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

14.03.2020, 12:49. Показов 3539. Ответов 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
1849 / 1191 / 501
Регистрация: 14.10.2018
Сообщений: 3,222
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
1849 / 1191 / 501
Регистрация: 14.10.2018
Сообщений: 3,222
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
1849 / 1191 / 501
Регистрация: 14.10.2018
Сообщений: 3,222
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
1849 / 1191 / 501
Регистрация: 14.10.2018
Сообщений: 3,222
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
Ответ Создать тему
Новые блоги и статьи
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача №1: при указании работ (справочник РаботыПоРемонтуСпецтехники),. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru