При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с фундаментальными различиями между обычными и управляемыми формами. Типичный сценарий — необходимость программно обойти элементы формы (например, флажки или поля ввода) и вычислить их сумму или проверить заполненность. Попытки сделать это «по старинке», напрямую обращаясь к коллекции элементов, часто приводят к ошибкам выполнения. В этой статье мы подробно разберем, почему возникают такие ошибки, как правильно получать значения реквизитов на сервере и как оптимизировать код с помощью логических операторов платформы.
Рассмотрим ситуацию, когда на управляемой форме внешней обработки расположено множество флажков (булевых реквизитов). Нам необходимо обойти их в цикле и посчитать сумму тех, которые отмечены («истина»).
Попытка реализовать это через следующий код приводит к ошибке:
&НаСервере
Функция ПроверочнаяСумма()
Для Каждого Рек из Элементы Цикл
Сообщить(рек.Имя + " - " + Строка(рек.Вид) + " - " + Объект[Рек]);
КонецЦикла;
КонецФункции
Проанализируем причины сбоя:
Объект[Рек] переменная Рек является объектом встроенного языка (тип ПолеФормы, ГруппаФормы или кнопка), а не строкой. Платформа 1С не умеет обращаться к свойствам структуры данных по ссылке на визуальный элемент управления, поэтому возвращает ошибку «Получение элемента по индексу для значения не определено».Объект[Рек.Имя] также может завершиться ошибкой «Поле объекта не обнаружено». Имя визуального элемента на форме далеко не всегда совпадает с именем реквизита данных, к которому он привязан. Кроме того, на форме могут присутствовать декорации, группы или кнопки, у которых вообще нет связанных данных.Если все интересующие нас флажки являются реквизитами самой обработки (то есть принадлежат объекту), наиболее надежным и лаконичным решением будет обращение к метаданным самого объекта, минуя коллекцию визуальных элементов формы.
На управляемой форме объект представлен типом данных ДанныеФормыСтруктура. Чтобы получить доступ к его метаданным, нам необходимо временно преобразовать его в прикладной объект на сервере. Для этого воспользуемся методом РеквизитФормыВЗначение().
Рассмотрим рабочий программный код:
&НаСервере
Функция ПроверочнаяСумма()
// Преобразуем данные формы в реальный объект обработки
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
КоличествоОтмеченных = 0;
// Обходим коллекцию реквизитов из метаданных объекта
Для Каждого Реквизит Из ОбработкаОбъект.Метаданные().Реквизиты Цикл
// Получаем значение реквизита по его имени
Значение = ОбработкаОбъект[Реквизит.Имя];
// Проверяем тип данных и значение флажка
Если ТипЗнч(Значение) = Тип("Булево") И Значение Тогда
КоличествоОтмеченных = КоличествоОтмеченных + 1;
КонецЕсли;
Сообщить(Реквизит.Имя + " - " + Реквизит.Тип + " - " + Значение);
КонецЦикла;
Возврат КоличествоОтмеченных;
КонецФункции
Преимущества этого подхода: Мы полностью застрахованы от ошибок, связанных с элементами оформления формы. Код анализирует только реальные данные объекта, независимо от того, выведены ли они на экран и как именно называются элементы интерфейса.
Если реквизиты добавлены непосредственно на форму (а не в объект обработки) или нам нужно работать именно с элементами интерфейса, мы должны использовать свойство ПутьКДанным элементов формы.
Разберем по шагам, как написать безопасный обход элементов:
&НаСервере
Функция ПроверочнаяСуммаПоЭлементам()
Сумма = 0;
Для Каждого Элемент Из Элементы Цикл
// Нам интересны только поля формы, у которых есть связь с данными
Если ТипЗнч(Элемент) = Тип("ПолеФормы") И Элемент.Вид = ВидПоляФормы.ПолеФлажка Тогда
ПутьКДанным = Элемент.ПутьКДанным;
// Проверяем, что путь ведет к реквизиту объекта (например, "Объект.ИмяФлажка")
Если СтрНачинаетсяС(ПутьКДанным, "Объект.") Тогда
// Извлекаем чистое имя реквизита
ИмяРеквизита = Сред(ПутьКДанным, 8); // отсекаем "Объект."
// Безопасно получаем значение из структуры Объект
Если Объект[ИмяРеквизита] = Истина Тогда
Сумма = Сумма + 1;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Сумма;
КонецФункции
В современных конфигурациях, использующих Библиотеку стандартных подсистем (БСП), для получения значений по пути к данным рекомендуется использовать готовые общие модули, например: ОбщегоНазначенияКлиентСервер.ПолучитьРеквизитФормыПоПути(ЭтаФорма, Элемент.ПутьКДанным). Это позволяет избежать ручного разбора строк путей.
В процессе обсуждения на форуме возник важный вопрос: как именно работают логические операторы И и ИЛИ в 1С? Проверяется ли вся цепочка условий или вычисления прекращаются при первом несоответствии?
В платформе 1С:Предприятие 8 реализован механизм «ленивых» (коротких) вычислений. Это означает, что логическое выражение вычисляется строго слева направо и только до тех пор, пока результат не станет однозначно ясен.
Рассмотрим, как это работает на практике:
Ложь, общее выражение гарантированно будет ложным. Платформа не будет вычислять правое выражение.Истина, общее выражение гарантированно будет истинным. Правая часть вычисляться не будет.Проанализируем классический пример безопасного кода, который часто применяется при проверках ссылочных типов:
Если СсылкаНаДокумент <> Неопределено И СсылкаНаДокумент.Проведен Тогда
// Выполняем действия с проведенным документом
КонецЕсли;
Если бы ленивых вычислений не существовало, то в случае, когда переменная СсылкаНаДокумент равна Неопределено, программа попыталась бы обратиться к свойству Проведен и выдала бы критическую ошибку «Значение не является значением объектного типа». Благодаря короткому вычислению в 1С 8.х, как только первая часть условия возвращает Ложь, система мгновенно прекращает дальнейшие проверки, предотвращая аварийное завершение работы.
Историческая справка: В старой платформе 1С:Предприятие 7.7 ленивых вычислений не было. Программистам приходилось конструировать громоздкие вложенные условия, чтобы избежать падения программы:
// Так приходилось писать в 1С 7.7
Если ПустоеЗначение(СсылкаНаДокумент) = 0 Тогда
Если СсылкаНаДокумент.Проведен = 1 Тогда
// Код обработки
КонецЕсли;
КонецЕсли;
Современный синтаксис 1С v8.3 позволяет писать этот код лаконично, безопасно и в одну строку.
Поскольку исходное обсуждение началось с вопроса о формате JSON, полезно упомянуть базовые возможности платформы для работы с этим стандартом. Платформа предоставляет мощные встроенные инструменты для сериализации и десериализации данных.
Для быстрой работы с JSON-строками используются методы ПрочитатьJSON() и ЗаписатьJSON(). Они позволяют преобразовывать коллекции 1С (такие как Структура, Массив, Соответствие) в JSON-строку и обратно буквально в несколько строк кода:
// Пример записи структуры в JSON
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ДанныеДляЗаписи = Новый Структура("Имя, Статус", "Масянька", Истина);
ЗаписатьJSON(Запись, ДанныеДляЗаписи);
РезультатСтрока = Запись.Закрыть();
Сообщить(РезультатСтрока); // Выведет {"Имя":"Масянька","Статус":true}
Для работы с большими файлами JSON рекомендуется использовать потоковые объекты ЧтениеJSON и ЗаписьJSON, которые позволяют читать и записывать данные порциями, минимизируя нагрузку на оперативную память сервера.