В процессе разработки расширений конфигурации 1С мы часто сталкиваемся с необходимостью изменить стандартное поведение типовых процедур. Аннотация &Вместо и метод ПродолжитьВызов() стали мощными инструментами в руках разработчика. Однако при попытке встроить ПродолжитьВызов() внутрь цикла мы можем встретиться с неожиданной ошибкой: «Вызов метода разрешен только в методах с аннотацией "Вместо"». Давайте разберем, почему так происходит и как правильно решить эту задачу.
Метод ПродолжитьВызов() архитектурно спроектирован для работы в рамках конкретного стека вызовов. Когда платформа выполняет процедуру, переопределенную через &Вместо, она ожидает, что вы отдадите управление типовому коду ровно один раз. Размещение ПродолжитьВызов() в теле цикла нарушает эту логику: на первой итерации метод отрабатывает корректно, но на второй итерации контекст «расширения» уже считается исчерпанным, так как основной метод был вызван, и платформа блокирует повторную попытку «продолжения».
Чтобы избежать ошибки и при этом сохранить возможность обработки массива данных, мы можем применить паттерн рекурсивного вызова. Вместо использования ПродолжитьВызов() внутри цикла, мы будем вызывать оригинальный метод напрямую. Так как наша процедура «замещает» типовую, вызов имени метода внутри нашей процедуры снова приведет к выполнению нашего кода. Чтобы это не привело к бесконечному циклу, мы предусмотрительно разделяем логику обработки массива и обработки единичного элемента.
Рассмотрим, как правильно структурировать код. Наша задача — проверить, передан ли массив, и если да, то запустить цикл обработки. Внутри цикла мы вызываем ту же процедуру, но уже с одним элементом, чтобы сработала ветка Иначе, где мы безопасно используем ПродолжитьВызов().
Вот как должен выглядеть ваш код:
&Вместо("ЗаполнитьПоПоступлению")
Процедура дор_ЗаполнитьПоПоступлению(ДанныеЗаполнения) Экспорт
Если ТипЗнч(ДанныеЗаполнения) = Тип("Массив") Тогда
// Обработка коллекции: запускаем цикл
Для Каждого ТекДокумент из ДанныеЗаполнения Цикл
Сообщить("Заполнение по документу: " + ТекДокумент);
// Вызываем процедуру рекурсивно для каждого элемента
ЗаполнитьПоПоступлению(ТекДокумент);
КонецЦикла;
Иначе
// Обработка одного элемента: здесь ПродолжитьВызов работает корректно
ПродолжитьВызов(ДанныеЗаполнения);
КонецЕсли;
КонецПроцедуры
Тип("Массив").ЗаполнитьПоПоступлению(ТекДокумент). Платформа снова перехватывает этот вызов нашим расширением.ДанныеЗаполнения — это уже не массив, а ссылка на документ (или другой тип).Иначе.ПродолжитьВызов(), который корректно обращается к типовому коду.При использовании подобных конструкций всегда учитывайте следующие моменты:
ПродолжитьВызов() обязательно передавайте все параметры, которые требует оригинальный метод. Если их пропустить, платформа выдаст ошибку несоответствия сигнатуры.Возврат перед ПродолжитьВызов(), чтобы результат работы типового кода был корректно возвращен вызывающему алгоритму.ЗаполнитьПоПоступлению), должен быть доступен для вызова в том контексте, где вы его используете.Используя данный подход, вы сохраняете чистоту кода, избегаете дублирования логики типовой конфигурации в своем расширении и обходите жесткие ограничения платформы 1С при работе со стеком вызовов.