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