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