В процессе разработки на платформе 1С:Предприятие часто возникают ситуации, когда необходимо выполнить фрагмент кода динамически. Одним из наиболее распространенных инструментов для этого является функция Вычислить(). Однако новички часто сталкиваются с проблемой: при попытке передать в вычисляемую функцию сложный объект (например, ХранилищеЗначения, ТаблицаЗначений или Структура), параметр внутри функции внезапно оказывается строкой, содержащей лишь название типа. Рассмотрим подробнее, почему это происходит и как правильно организовать передачу данных.
Проанализируем ситуацию, с которой столкнулся автор темы. В его исходном коде была предпринята попытка передать объект через конкатенацию строк. Выглядело это следующим образом:
Процедура КнопкаНажатие(Элемент)
Параметр = новый ХранилищеЗначения(ТабЧасть);
Проверка = Вычислить("ПолучениеТаблицы(" + Параметр + ")"); // ОШИБКА ЗДЕСЬ
п = Проверка;
КонецПроцедуры
Выясним причину, по которой этот код работает некорректно. Когда мы используем оператор "+" между строкой "ПолучениеТаблицы(" и объектом Параметр, система 1С применяет механизм неявного приведения типов. Поскольку левый операнд является строкой, платформа пытается преобразовать ХранилищеЗначения тоже в строку.
Для большинства сложных объектов строковое представление — это просто их тип. В итоге в функцию Вычислить() передается текст "ПолучениеТаблицы(ХранилищеЗначения)". При попытке исполнения этого кода система ищет переменную с именем ХранилищеЗначения, не находит её (или находит тип данных) и выдает ошибку, либо передает пустую строку. Данные, содержащиеся внутри хранилища, полностью теряются.
Для того чтобы передать объект «как есть», сохранив его тип и содержимое, необходимо передавать в строке вычисления имя переменной, а не её значение. Разберем исправленный вариант кода:
Проверка = Вычислить("ПолучениеТаблицы(Параметр)");
Почему это работает? Рассмотрим механизм работы контекста. Функция Вычислить() исполняет код в контексте того модуля и той процедуры, где она была вызвана. Это означает, что если в процедуре КнопкаНажатие объявлена локальная переменная Параметр, то динамический код внутри Вычислить() «видит» эту переменную по её имени. Система берет ссылку на реальный объект в памяти и передает его в функцию ПолучениеТаблицы точно так же, как если бы вы написали этот вызов в обычном коде.
Разберем, какой метод лучше использовать в зависимости от задачи. В 1С существует два основных способа динамического исполнения кода:
Выполнить() не возвращает значение. Чтобы получить результат из Выполнить(), нужно внутри строки кода присвоить результат какой-либо переменной, доступной в контексте.Посмотрим на пример использования Выполнить() для той же задачи:
// Переменная 'Результат' должна быть объявлена заранее
Результат = Неопределено;
ТекстКода = "Результат = ПолучениеТаблицы(Параметр)";
Выполнить(ТекстКода);
// Теперь в переменной 'Результат' лежит возвращаемое значение функции
В современной разработке (особенно на управляемых формах) передача тяжелых объектов через Вычислить() может быть не самым эффективным решением. Если ваша задача — передать данные между клиентом и сервером или между различными формами, рекомендуется использовать Временное хранилище.
Проанализируем ситуацию: вместо того чтобы «гонять» всю таблицу значений через параметры, мы можем поместить её в хранилище и передать только короткий адрес (строку GUID). Это значительно снижает нагрузку на память и сетевой трафик.
Пример реализации через временное хранилище:
// Помещаем данные в хранилище
АдресХранилища = ПоместитьВоВременноеХранилище(ТабЧасть, ЭтаФорма.УникальныйИдентификатор);
// В динамическом коде передаем только адрес
Результат = Вычислить("ОбработатьДанныеПоАдресу(АдресХранилища)");
// Внутри функции получаем данные обратно
Функция ОбработатьДанныеПоАдресу(Адрес)
Данные = ПолучитьИзВременногоХранилища(Адрес);
// ... логика обработки ...
Возврат Истина;
КонецФункции
Использование Вычислить() и Выполнить() требует осторожности. Рассмотрим основные правила, которые помогут избежать проблем в будущем:
Параметр используйте ИсходнаяТаблицаЗначений или ДанныеДляРасчета. Это упрощает отладку динамического кода.Вычислить() не проверяются конфигуратором при компиляции. Они проявятся только в момент выполнения программы (в рантайме).Подведем итог: главная хитрость работы с Вычислить() заключается в том, чтобы воспринимать строку внутри метода как обычный программный код, который просто записан в кавычках. Все переменные, которые доступны в месте вызова, будут доступны и внутри этой строки по их именам без каких-либо дополнительных преобразований.