Как динамически обратиться к свойству или реквизиту объекта в 1С по строковому имени?

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

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

Классический пример такой задачи: у нас есть массив имен рисунков в табличном документе (например, "D1", "D2", "D3"), и нам нужно в цикле обойти их все и изменить их свойства (например, видимость или ширину). Напрямую написать ТабДок.Рисунки.ИмяЭлемента мы не можем, так как компилятор будет искать буквально реквизит с именем "ИмяЭлемента", а не использовать значение этой переменной.

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

Способ 1. Использование квадратных скобок [] (Рекомендуемый стандарт)

Использование квадратных скобок — это самый простой, быстрый и безопасный способ динамического обращения к свойствам объектов в среде «1С:Предприятие». Этот синтаксис поддерживается платформой во множестве контекстов и работает как прямая альтернатива привычному обращению через точку.

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


МассивЭлементов = Новый Массив;
МассивЭлементов.Добавить("D1");
МассивЭлементов.Добавить("D2");
МассивЭлементов.Добавить("D3");

Для Каждого ИмяРисунка Из МассивЭлементов Цикл
    // Обращаемся к рисунку динамически по его имени
    ЭлементСхемы = ТабДок.Рисунки[ИмяРисунка];
    
    // Теперь мы можем работать с объектом рисунка
    Если ЭлементСхемы <> Неопределено Тогда
        ЭлементСхемы.Видимость = Ложь;
    КонецЕсли;
КонецЦикла;

Этот подход работает не только для рисунков табличного документа. Проанализируем, где еще мы можем использовать квадратные скобки для динамического доступа:

  1. Реквизиты объектов базы данных и ссылок: Если у вас есть ссылка на элемент справочника (например, СправочникСсылка.Номенклатура) или сам объект, вы можете получить значение любого его реквизита, передав его имя в виде строки: Товар[ИмяРеквизита].
  2. Табличные части объектов: Обратиться к табличной части документа или справочника можно аналогичным образом: ДокументОбъект[ИмяТабличнойЧасти].
  3. Элементы и реквизиты управляемой формы: На управляемой форме мы можем динамически обращаться к элементам интерфейса через коллекцию элементов: Элементы[ИмяЭлементаФормы].Доступность = Ложь;, а к реквизитам самой формы — через ЭтаФорма[ИмяРеквизита].
  4. Универсальные коллекции данных: Структуры, Соответствия, а также строки Таблиц значений и Деревьев значений по умолчанию поддерживают обращение по имени ключа/колонки через квадратные скобки: ТекущаяСтрока[ИмяКолонки] = Значение;.

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

Способ 2. Использование встроенной функции Вычислить()

Что делать, если структура объекта не поддерживает обращение через квадратные скобки, или если вам нужно динамически вычислить целое выражение? В таких ситуациях на помощь приходит встроенная функция платформы Вычислить().

Функция Вычислить(<СтроковоеВыражение>) компилирует и выполняет переданную в нее строку "на лету" как выражение и возвращает полученный результат.

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


ИмяЭлемента = "D1";
// Формируем строку выражения: "ТабДок.Рисунки.D1"
СтрокаВыражения = "ТабДок.Рисунки." + ИмяЭлемента;

// Выполняем вычисление и получаем готовый объект
ЭлементСхемы = Вычислить(СтрокаВыражения);

Также данный метод отлично подходит, если вам нужно динамически запустить функцию, возвращающую значение:


ИмяФункции = "ПолучитьТекущуюДату";
Результат = Вычислить(ИмяФункции + "()");

Критическое ограничение функции Вычислить(): Переданное выражение обязательно должно возвращать результат (значение). Вы не можете использовать эту функцию для выполнения операций присваивания или вызова процедур, которые ничего не возвращают. Например, код Вычислить("Переменная = 10") не присвоит переменной значение 10, а выполнит логическое сравнение и вернет Ложь или Истина.

Способ 3. Использование оператора Выполнить()

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

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

Посмотрим на практический пример использования оператора Выполнить() для динамического изменения свойства объекта:


ИмяЭлемента = "D1";
ИмяСвойства = "Видимость";
НовоеЗначение = "Ложь";

// Формируем полноценную строку кода: "ТабДок.Рисунки.D1.Видимость = Ложь;"
СтрокаКода = "ТабДок.Рисунки." + ИмяЭлемента + "." + ИмяСвойства + " = " + НовоеЗначение + ";";

Выполнить(СтрокаКода);

В данном случае платформа успешно интерпретирует строку как команду присвоения значения и выполнит её.

Сравнение производительности и безопасности: почему скобки всегда лучше?

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

  1. Существенное падение производительности. При каждом вызове функций Выполнить() или Вычислить() платформе приходится компилировать переданную текстовую строку в исполняемый байт-код прямо во время работы программы. Если запустить такой вызов внутри цикла по тысячам строк табличной части или записей базы данных, производительность системы упадет в десятки раз по сравнению с обращением через квадратные скобки `[]`, работающим на уровне платформы мгновенно.
  2. Уязвимость кода (инъекция кода). Использование динамического исполнения кода может быть небезопасным, если параметры для компилируемой строки приходят из внешних или пользовательских источников. Злоумышленник может передать в строковую переменную деструктивный код (например, удаление критически важных данных), который система послушно выполнит с правами текущего пользователя.
  3. Ограничения среды исполнения. В безопасном режиме работы программы (например, во внешних обработках, запущенных в облачных сервисах 1С:Фреш) использование динамического исполнения кода через Выполнить() или Вычислить() может быть полностью заблокировано политиками безопасности платформы.

Рекомендации и лучшие практики при динамической работе

Для того чтобы ваш код оставался чистым, быстрым и безопасным, мы рекомендуем придерживаться следующих правил:

1. Всегда отдавайте приоритет квадратным скобкам. Если у вас стоит задача прочитать или записать реквизит объекта, воспользоваться скобками — наилучший выбор.

2. Проверяйте существование реквизита перед обращением. Динамическое обращение к несуществующему свойству приведет к аварийному завершению работы программы (вызовет исключение). Чтобы этого избежать, перед обращением проверяйте метаданные объекта. Рассмотрим пример такой проверки для реквизитов справочника:


ИмяРеквизита = "Артикул";
МетаданныеСправочника = Метаданные.Справочники.Номенклатура;

// Проверяем, существует ли реквизит с таким именем в метаданных
Если МетаданныеСправочника.Реквизиты.Найти(ИмяРеквизита) <> Неопределено Тогда
    // Теперь обращение безопасно
    ЗначениеРеквизита = СсылкаНаТовар[ИмяРеквизита];
Иначе
    ВызватьИсключение "У справочника Номенклатура отсутствует реквизит: " + ИмяРеквизита;
КонецЕсли;

3. Пользуйтесь универсальным методом ЗаполнитьЗначенияСвойств(). Если ваша задача заключается в том, чтобы скопировать значения одноименных колонок или реквизитов из одного объекта в другой (например, из строки таблицы значений в строку табличной части документа), вам совершенно не нужно организовывать циклы с квадратными скобками. Достаточно использовать одну быструю встроенную процедуру платформы:


// Копирует все совпадающие по именам свойства из Источника в Приемник
ЗаполнитьЗначенияСвойств(СтрокаДокумента, СтрокаТаблицы);

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

← На главную