Как изменить одну строку кода в расширении 1С без копирования всей функции?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке в среде 1С:Предприятие с использованием расширений программисты часто сталкиваются с классической дилеммой. Представьте ситуацию: в типовой конфигурации есть процедура или функция на несколько сотен строк. В самой середине этого кода вызывается другой метод, и вам необходимо изменить лишь один передаваемый параметр или добавить небольшое условие. Неужели ради изменения одной строчки придется копировать весь огромный метод в расширение через аннотацию &Вместо?

Копирование метода целиком («намертво») создает огромный долг технической поддержки. При выходе очередного обновления от поставщика конфигурации любые изменения в этом типовом методе (исправление критических багов, изменение логики, оптимизация) пройдут мимо вашей информационной базы, так как расширение полностью перекроет стандартный код своим устаревшим аналогом. В этой статье мы подробно разберем, как решить эту задачу изящно, используя современные возможности платформы 1С и правильные архитектурные приемы.

Способ №1. Современный платформенный механизм: Аннотация &ИзменениеИКонтроль

Начиная с версии платформы 1С:Предприятие 8.3.15, разработчикам доступен специализированный инструмент для точечного изменения кода — аннотация &ИзменениеИКонтроль. Этот механизм позволяет заимствовать метод в расширение, но менять в нем только конкретные строки с помощью специальных директив препроцессора.

Разберем по шагам, как работает этот механизм на практике:

  1. Мы заимствуем необходимую процедуру или функцию в свое расширение, выбрав тип вызова «Вызывать вместо (с контролем)».
  2. В модуле расширения создается шаблон метода с аннотацией &ИзменениеИКонтроль, полностью повторяющий исходный код.
  3. Код, который необходимо убрать или изменить (например, исходный вызов функции со старыми параметрами), мы обрамляем директивами #Удаление и #КонецУдаления.
  4. Новый измененный код мы пишем сразу после этого, оборачивая его в директивы #Вставка и #КонецВставки.

Проанализируем ситуацию на конкретном примере. Предположим, в типовой конфигурации есть следующий метод:


Процедура РассчитатьСкидкуПокупателя(ДокументСсылка, БазоваяСкидка)
    // ... какой-то длинный типовой код ...
    ПроцентСкидки = ПолучитьПерсональныйПроцент(ДокументСсылка, Истина);
    // ... продолжение длинного типового кода ...
КонецПроцедуры

Нам необходимо изменить передаваемый параметр во вспомогательной функции: вместо Истина передать Ложь. Посмотрим на пример реализации этой задачи в расширении с помощью контроля кода:


&ИзменениеИКонтроль("РассчитатьСкидкуПокупателя")
Процедура Расш1_РассчитатьСкидкуПокупателя(ДокументСсылка, БазоваяСкидка)
    // ... весь длинный типовой код автоматически переносится сюда ...
    #Удаление
    ПроцентСкидки = ПолучитьПерсональныйПроцент(ДокументСсылка, Истина);
    #КонецУдаления
    #Вставка
    ПроцентСкидки = ПолучитьПерсональныйПроцент(ДокументСсылка, Ложь);
    #КонецВставки
    // ... продолжение длинного типового кода ...
КонецПроцедуры

В чем главное преимущество перед &Вместо? При обновлении конфигурации платформа автоматически сравнивает оригинальный код метода поставщика с тем кодом, который находится у вас в расширении (вне блоков вставки и удаления). Если разработчики 1С изменят логику работы в других частях этой процедуры, платформа предупредит вас о несовместимости, предотвращая появление скрытых и трудноуловимых ошибок.

Эволюция контроля кода в новых версиях платформы (8.3.18 – 8.3.25)

В ранних версиях платформы механизм контроля часто критиковали за избыточную чувствительность. Однако фирма «1С» проделала большую работу над ошибками в последних релизах:

Способ №2. Архитектурная альтернатива: Перехват вызываемого метода

Рассмотрим подробнее альтернативный подход, о котором часто забывают разработчики. Если вам нужно изменить параметры, передаваемые в какую-то процедуру или функцию в середине кода, не обязательно вмешиваться в работу вызывающего (родительского) метода.

Проанализируем ситуацию. Если вызываемый метод (в нашем примере это ПолучитьПерсональныйПроцент) является экспортным или доступен для заимствования в текущем модуле, гораздо правильнее и безопаснее перехватить именно его!

Мы можем применить аннотацию &Вместо или &Перед для вызываемого метода, чтобы подменить параметры прямо на «входе». Посмотрим, как это выглядит в коде расширения:


&Вместо("ПолучитьПерсональныйПроцент")
Функция Расш1_ПолучитьПерсональныйПроцент(ДокументСсылка, ИсходныйПараметр)
    
    // Переопределяем логику параметра прямо «на лету»
    НовыйПараметр = Ложь; 
    
    // Вызываем оригинальный метод с нашими скорректированными данными
    Результат = ПродолжитьВызов(ДокументСсылка, НовыйПараметр);
    
    Возврат Результат;
КонецФункции

Такой подход обладает колоссальными преимуществами:

  1. Вам вообще не нужно трогать огромную родительскую функцию РассчитатьСкидкуПокупателя.
  2. При любых обновлениях родительской функции ваше расширение гарантированно продолжит работать стабильно и без сбоев.
  3. Код расширения остается лаконичным, чистым и понятным для других разработчиков.

Однако помните о важном ограничении: этот способ применим только в том случае, если вызываемый метод не используется в других местах этого же модуля с оригинальными параметрами, которые вам изменять не нужно. Если этот метод вызывается еще из десятка процедур, и там логика должна остаться прежней, то придется либо ставить дополнительные условия (например, проверять тип или реквизиты передаваемого документа), либо возвращаться к первому способу с использованием &ИзменениеИКонтроль.

Подведем итоги

Мы разобрали два наиболее эффективных и безопасных способа точечного изменения логики в середине функций:

Откажитесь от практики слепого копирования кода типовых методов. Использование правильных инструментов расширения платформы 1С сбережет ваше время и обеспечит легкую поддержку конфигурации в будущем.

← На главную