При разработке сложных, гибких алгоритмов или универсальных обработок в системе «1С:Предприятие» программисты регулярно сталкиваются с необходимостью обратиться к свойству, реквизиту или методу объекта динамически. Это означает, что точное имя свойства на этапе написания программного кода неизвестно — оно может храниться в переменной, считываться из настроек, приходить из внешнего источника или перебираться в цикле из массива строк.
Классический пример такой задачи: у нас есть массив имен рисунков в табличном документе (например, "D1", "D2", "D3"), и нам нужно в цикле обойти их все и изменить их свойства (например, видимость или ширину). Напрямую написать ТабДок.Рисунки.ИмяЭлемента мы не можем, так как компилятор будет искать буквально реквизит с именем "ИмяЭлемента", а не использовать значение этой переменной.
В этой статье мы подробно рассмотрим, как решить эту задачу, разберем по шагам наиболее эффективные и безопасные способы динамического обращения к свойствам и методам в 1С, а также проанализируем возможные подводные камни, связанные с производительностью кода.
Использование квадратных скобок — это самый простой, быстрый и безопасный способ динамического обращения к свойствам объектов в среде «1С:Предприятие». Этот синтаксис поддерживается платформой во множестве контекстов и работает как прямая альтернатива привычному обращению через точку.
Давайте посмотрим, как решить задачу автора темы с рисунками в табличном документе. Вместо того чтобы пытаться подставить строку после точки, мы передаем строковую переменную внутрь квадратных скобок коллекции:
МассивЭлементов = Новый Массив;
МассивЭлементов.Добавить("D1");
МассивЭлементов.Добавить("D2");
МассивЭлементов.Добавить("D3");
Для Каждого ИмяРисунка Из МассивЭлементов Цикл
// Обращаемся к рисунку динамически по его имени
ЭлементСхемы = ТабДок.Рисунки[ИмяРисунка];
// Теперь мы можем работать с объектом рисунка
Если ЭлементСхемы <> Неопределено Тогда
ЭлементСхемы.Видимость = Ложь;
КонецЕсли;
КонецЦикла;
Этот подход работает не только для рисунков табличного документа. Проанализируем, где еще мы можем использовать квадратные скобки для динамического доступа:
СправочникСсылка.Номенклатура) или сам объект, вы можете получить значение любого его реквизита, передав его имя в виде строки: Товар[ИмяРеквизита].ДокументОбъект[ИмяТабличнойЧасти].Элементы[ИмяЭлементаФормы].Доступность = Ложь;, а к реквизитам самой формы — через ЭтаФорма[ИмяРеквизита].ТекущаяСтрока[ИмяКолонки] = Значение;.Важное ограничение: Квадратные скобки позволяют обращаться только к свойствам, реквизитам или элементам коллекций. Вызвать метод (процедуру или функцию) объекта с их помощью напрямую не получится.
Что делать, если структура объекта не поддерживает обращение через квадратные скобки, или если вам нужно динамически вычислить целое выражение? В таких ситуациях на помощь приходит встроенная функция платформы Вычислить().
Функция Вычислить(<СтроковоеВыражение>) компилирует и выполняет переданную в нее строку "на лету" как выражение и возвращает полученный результат.
Давайте разберем по шагам пример динамического получения свойства через эту функцию:
ИмяЭлемента = "D1";
// Формируем строку выражения: "ТабДок.Рисунки.D1"
СтрокаВыражения = "ТабДок.Рисунки." + ИмяЭлемента;
// Выполняем вычисление и получаем готовый объект
ЭлементСхемы = Вычислить(СтрокаВыражения);
Также данный метод отлично подходит, если вам нужно динамически запустить функцию, возвращающую значение:
ИмяФункции = "ПолучитьТекущуюДату";
Результат = Вычислить(ИмяФункции + "()");
Критическое ограничение функции Вычислить(): Переданное выражение обязательно должно возвращать результат (значение). Вы не можете использовать эту функцию для выполнения операций присваивания или вызова процедур, которые ничего не возвращают. Например, код Вычислить("Переменная = 10") не присвоит переменной значение 10, а выполнит логическое сравнение и вернет Ложь или Истина.
Если вам необходимо динамически выполнить полноценное действие, операцию присваивания, запустить процедуру или даже выполнить целый блок кода, то вместо Вычислить() необходимо использовать оператор Выполнить().
Оператор Выполнить(<СтрокаКода>) принимает на вход строку, содержащую один или несколько операторов языка 1С, и выполняет их в текущем контексте. При этом данный оператор не возвращает никакого значения.
Посмотрим на практический пример использования оператора Выполнить() для динамического изменения свойства объекта:
ИмяЭлемента = "D1";
ИмяСвойства = "Видимость";
НовоеЗначение = "Ложь";
// Формируем полноценную строку кода: "ТабДок.Рисунки.D1.Видимость = Ложь;"
СтрокаКода = "ТабДок.Рисунки." + ИмяЭлемента + "." + ИмяСвойства + " = " + НовоеЗначение + ";";
Выполнить(СтрокаКода);
В данном случае платформа успешно интерпретирует строку как команду присвоения значения и выполнит её.
Несмотря на кажущуюся универсальность функций Вычислить() и Выполнить(), практикующие разработчики стараются избегать их применения в боевом коде без крайней необходимости. Выясним основные причины такой осторожности:
Выполнить() или Вычислить() платформе приходится компилировать переданную текстовую строку в исполняемый байт-код прямо во время работы программы. Если запустить такой вызов внутри цикла по тысячам строк табличной части или записей базы данных, производительность системы упадет в десятки раз по сравнению с обращением через квадратные скобки `[]`, работающим на уровне платформы мгновенно.Выполнить() или Вычислить() может быть полностью заблокировано политиками безопасности платформы.Для того чтобы ваш код оставался чистым, быстрым и безопасным, мы рекомендуем придерживаться следующих правил:
1. Всегда отдавайте приоритет квадратным скобкам. Если у вас стоит задача прочитать или записать реквизит объекта, воспользоваться скобками — наилучший выбор.
2. Проверяйте существование реквизита перед обращением. Динамическое обращение к несуществующему свойству приведет к аварийному завершению работы программы (вызовет исключение). Чтобы этого избежать, перед обращением проверяйте метаданные объекта. Рассмотрим пример такой проверки для реквизитов справочника:
ИмяРеквизита = "Артикул";
МетаданныеСправочника = Метаданные.Справочники.Номенклатура;
// Проверяем, существует ли реквизит с таким именем в метаданных
Если МетаданныеСправочника.Реквизиты.Найти(ИмяРеквизита) <> Неопределено Тогда
// Теперь обращение безопасно
ЗначениеРеквизита = СсылкаНаТовар[ИмяРеквизита];
Иначе
ВызватьИсключение "У справочника Номенклатура отсутствует реквизит: " + ИмяРеквизита;
КонецЕсли;
3. Пользуйтесь универсальным методом ЗаполнитьЗначенияСвойств(). Если ваша задача заключается в том, чтобы скопировать значения одноименных колонок или реквизитов из одного объекта в другой (например, из строки таблицы значений в строку табличной части документа), вам совершенно не нужно организовывать циклы с квадратными скобками. Достаточно использовать одну быструю встроенную процедуру платформы:
// Копирует все совпадающие по именам свойства из Источника в Приемник
ЗаполнитьЗначенияСвойств(СтрокаДокумента, СтрокаТаблицы);
Подводя итог, можно сказать: платформа «1С:Предприятие» предоставляет разработчику богатый инструментарий для динамической работы с объектами. Понимание различий между квадратными скобками, функцией Вычислить() и оператором Выполнить() позволяет писать не просто рабочий, но и максимально оптимизированный, отказоустойчивый код.