В практике разработки на платформе 1С:Предприятие часто встречаются задачи, когда структура данных содержит однотипные поля, различающиеся только цифровым суффиксом. Классический пример — табель учета рабочего времени или плоская таблица, где дни месяца представлены колонками: День1, День2 ... День31.
При обработке таких данных возникает закономерный вопрос: как обратиться к конкретному полю, если номер дня хранится в переменной? Написание конструкции Если...ИначеЕсли на 31 ветку является крайне неэффективным и трудно поддерживаемым решением. В этой статье мы подробно разберем, как элегантно решить эту задачу, используя возможности встроенного языка 1С, и рассмотрим лучшие практики работы с динамическими именами свойств.
Рассмотрим ситуацию, описанную автором вопроса. У нас есть выборка из результата запроса или строка таблицы значений, которая содержит множество полей: ВидВремени1, ВидВремени2 и так далее. Нам нужно получить значение одного из этих полей, основываясь на текущей дате или переменной, содержащей число.
Прямое обращение через точку работает только если мы знаем имя поля на этапе написания кода:
// Это работает, но имя жестко задано
Значение = Выборка.ВидВремени15;
Однако, если число 15 хранится в переменной НомерДня, мы не можем написать Выборка.ВидВремениНомерДня. Интерпретатор будет искать поле именно с таким буквальным названием, которого не существует. Нам нужен механизм преобразования имени поля из строки в обращение к свойству.
[]Самым эффективным и правильным способом решения данной задачи является использование оператора доступа к коллекции по индексу или ключу — []. В платформе 1С множество объектов (Выборка из запроса, Строка таблицы значений, Структура, ДанныеФормыСтруктура) поддерживают обращение к своим свойствам через строковое имя.
Разберем синтаксис на примере. Допустим, у нас есть переменная НомерДня, равная 21.
НомерДня = 21;
// Формируем имя поля конкатенацией (сложением) строк
ИмяПоля = "ВидВремени" + НомерДня;
// Обращаемся к коллекции, используя сформированную строку как ключ
НужноеЗначение = ВыборкаДетальныеЗаписи[ИмяПоля];
Этот код делает ровно то же самое, что и запись ВыборкаДетальныеЗаписи.ВидВремени21, но позволяет менять номер дня динамически во время выполнения программы.
СтрШаблонХотя обычное сложение строк (конкатенация) работает корректно, при формировании сложных имен переменных рекомендуется использовать функцию СтрШаблон. Это делает код более чистым и понятным, а также избавляет от потенциальных ошибок при преобразовании типов.
Посмотрим, как это выглядит на практике:
// Получаем день из текущей даты сеанса
ТекущийДень = День(ТекущаяДатаСеанса());
// Формируем имя поля через шаблон
// %1 будет заменено на значение переменной ТекущийДень
ИмяПоля = СтрШаблон("ВидВремени%1", ТекущийДень);
// Получаем значение
Значение = ВыборкаДетальныеЗаписи[ИмяПоля];
Использование СтрШаблон особенно полезно, если имя поля состоит из нескольких частей или требует форматирования.
Важно понимать, что подход с квадратными скобками универсален. Давайте рассмотрим различные сценарии, где он применим, чтобы вы могли использовать этот инструмент максимально широко.
Если вы перебираете строки таблицы значений, вы можете обращаться к колонкам динамически:
Для Каждого СтрокаТЗ Из МояТаблица Цикл
Для Счетчик = 1 По 10 Цикл
// Читаем значение из колонок "Показатель1"..."Показатель10"
Сумма = Сумма + СтрокаТЗ["Показатель" + Счетчик];
КонецЦикла;
КонецЦикла;
Структуры изначально созданы для хранения пар "Ключ-Значение". Обращение Структура.Ключ — это просто "синтаксический сахар" для Структура["Ключ"].
На клиенте (в модуле формы) часто возникает необходимость управлять видимостью или доступностью группы элементов (например, кнопок или полей ввода), имеющих нумерацию. Коллекция Элементы также поддерживает этот синтаксис:
// Скрываем кнопки Кнопка1, Кнопка2... Кнопка5
Для Инд = 1 По 5 Цикл
Элементы["Кнопка" + Инд].Видимость = Ложь;
КонецЦикла;
При использовании динамического обращения к свойствам мы теряем контроль компилятора. Если вы напишете Выборка.НесуществующееПоле, конфигуратор выдаст ошибку при проверке модуля. Если же вы напишете Выборка["НесуществующееПоле"], ошибка возникнет только в момент выполнения кода у пользователя ("Поле объекта не обнаружено").
Рассмотрим, как обезопасить код.
Для структур существует метод Свойство, который проверяет наличие ключа.
Если ПараметрыДанных.Свойство("ВидВремени" + НомерДня, НайденноеЗначение) Тогда
// Поле существует, значение помещено в переменную НайденноеЗначение
Сообщить(НайденноеЗначение);
Иначе
Сообщить("Поле для дня " + НомерДня + " не найдено!");
КонецЕсли;
Для таблицы значений нужно проверять коллекцию колонок.
ИмяКолонки = "Реквизит" + Номер;
Если ТЗ.Колонки.Найти(ИмяКолонки) <> Неопределено Тогда
Значение = СтрокаТЗ[ИмяКолонки];
КонецЕсли;
У объекта ВыборкаИзРезультатаЗапроса нет встроенного метода для проверки наличия колонки. Поэтому, если есть вероятность, что поле может отсутствовать, лучше предварительно выгрузить выборку в таблицу значений или строго контролировать текст запроса.
Иногда проблему лучше решать не на этапе обработки выборки, а на этапе получения данных. Если в таблице базы данных сотни колонок, а вам нужна только одна, вытягивать все данные и потом выбирать нужное программно — неоптимально с точки зрения производительности.
В таких случаях сформируйте текст запроса динамически:
ТекстЗапроса =
"ВЫБРАТЬ
| Т.Сотрудник,
| Т.ВидВремени" + НомерДня + " КАК ВидВремениЗаДень
|ИЗ
| Документ.Табель.Данные КАК Т
|ГДЕ
| Т.Ссылка = &Ссылка";
Запрос.Текст = ТекстЗапроса;
// ... выполнение запроса
В этом случае в выборке всегда будет поле с фиксированным алиасом ВидВремениЗаДень, и вам не придется использовать динамическое обращение к выборке.
Вычислить()Иногда новички пытаются использовать глобальную функцию Вычислить() (или Eval в других языках) для доступа к переменным:
// ПЛОХОЙ ПРИМЕР, НЕ ДЕЛАЙТЕ ТАК
Значение = Вычислить("Выборка.ВидВремени" + НомерДня);
Почему этого следует избегать:
Вычислить заставляет платформу компилировать фрагмент кода "на лету", что значительно медленнее прямого доступа через [].Подведем итог. Чтобы обратиться к полю выборки, структуры или таблицы, имя которого содержит изменяющуюся часть (номер):
Если.+ или функцию СтрШаблон.Коллекция[ИмяПоля].