Как получить значение локальной переменной из процедуры основной конфигурации в расширении?

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

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

Давайте разберем, почему прямой подход вызывает ошибку, как работает память в 1С при вызове методов, и какие существуют правильные способы решения этой задачи.

Почему переменная недоступна в аннотации &После?

Для начала проанализируем механизм выполнения кода. Когда вы используете аннотацию &После, платформа выполняет код следующим образом:

  1. Запускается процедура из основной конфигурации.
  2. В стеке памяти выделяется место под локальные переменные этой процедуры (в нашем примере — переменная А).
  3. Выполняется код основной процедуры.
  4. Процедура завершается (достигает КонецПроцедуры).
  5. Важный момент: Стек памяти очищается, и все локальные переменные физически уничтожаются.
  6. Только после этого запускается ваш метод из расширения с аннотацией &После.

Таким образом, попытка обратиться к переменной А в методе расширения обречена на провал — этой переменной уже не существует в природе. Метод расширения &После видит только то, что ему передали в параметрах, или переменные уровня модуля (если они экспортные), но никак не внутреннюю "кухню" завершившейся процедуры.

Решение 1: Использование аннотации &ИзменениеИКонтроль (Рекомендуемое)

Начиная с версии платформы 8.3.15, наиболее правильным и безопасным способом "вклиниться" в код и получить доступ к локальным переменным является использование аннотации &ИзменениеИКонтроль. Этот механизм позволяет не заменять процедуру целиком, а внедрять свой код в определенные места исходной процедуры.

При использовании этого метода платформа фактически "склеивает" текст основной процедуры и вашей вставки, компилируя их как единое целое. Благодаря этому, ваш код оказывается внутри одной области видимости с переменными основной конфигурации.

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


Процедура Переменная1()
    А = 100;
    // ... какой-то код конфигурации ...
КонецПроцедуры

Чтобы получить значение А, создадим в расширении процедуру такого вида:


&ИзменениеИКонтроль("Переменная1")
Процедура Расш_Переменная1()
    
    // Начало повторяет код основной конфигурации, 
    // но платформа позволяет нам использовать теги вставки
    
    А = 100; 
    
    #Вставка
    // В этом месте мы находимся ВНУТРИ контекста процедуры.
    // Переменная А доступна для чтения и изменения.
    Сообщить("Значение переменной А: " + А);
    
    // Можно даже изменить её логику
    А = А + 50; 
    #КонецВставки
    
    // ... продолжение кода конфигурации ...
КонецПроцедуры

Преимущества этого метода:

Решение 2: Использование аннотации &Вместо (Копирование кода)

Если версия платформы старая или использование &ИзменениеИКонтроль по каким-то причинам невозможно (например, слишком сложная структура кода), можно применить аннотацию &Вместо.

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

Пример реализации:


&Вместо("Переменная1")
Процедура Расш_Переменная1()
    // Полностью скопированный код из основной конфигурации
    А = 100;
    
    // Ваш добавленный код
    Сообщить(А);
    
    // Продолжение скопированного кода...
КонецПроцедуры

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

Решение 3: Через параметры процедуры (Если возможно)

Иногда нам везет, и в процедуре есть параметр типа Структура, который передается дальше по цепочке вызовов или возвращается из функции. Рассмотрим этот вариант, хотя он зависит от архитектуры конкретной процедуры.

Если исходная процедура выглядит так:


Процедура ОбработатьДанные(Параметры)
    А = 100;
    // ...
    // Если разработчик предусмотрел сохранение данных в параметр
    Параметры.Вставить("РезультатА", А);
КонецПроцедуры

Тогда в расширении с аннотацией &После мы можем прочитать это значение, так как переменная Параметры передается по ссылке и сохраняет изменения:


&После("ОбработатьДанные")
Процедура Расш_ОбработатьДанные(Параметры)
    // Переменной А уже нет, но Параметры остались
    Если Параметры.Свойство("РезультатА") Тогда
        Сообщить(Параметры.РезультатА);
    КонецЕсли;
КонецПроцедуры

К сожалению, добавить новый параметр в сигнатуру метода через расширение нельзя. Мы можем работать только с тем набором параметров, который определен в основной конфигурации.

Резюме

Давайте подведем итог. Локальные переменные "живут" только внутри процедуры и только во время её выполнения. Чтобы получить к ним доступ из расширения:

  1. Лучший способ: используйте аннотацию &ИзменениеИКонтроль. Она позволяет встроить ваш код внутрь процедуры, сохраняя доступ к контексту.
  2. Запасной способ: используйте аннотацию &Вместо и полностью скопируйте код процедуры, добавив свои действия. Помните о рисках при обновлении.
  3. Аннотации &Перед и &После не подходят для доступа к локальным переменным, так как работают за пределами области видимости оригинальной процедуры.
← На главную