При разработке универсальных механизмов загрузки данных, интеграций или парсинга файлов перед разработчиком часто возникает задача: на входе есть строковое значение (например, "125", "01.02.2023" или "Истина"), а также информация о целевом типе, к которому эти данные необходимо преобразовать. При этом тип может храниться в переменной как строковое имя, тип метаданных или объект типа Тип.
Рассмотрим подробно, какие инструменты платформы 1С:Предприятие позволяют решить эту задачу наиболее универсально, надежно и без написания громоздких конструкций Если ... Тогда ... ИначеЕсли.
Разберем самый стандартный и правильный платформенный подход. В платформе 1С:Предприятие существует специализированный объект ОписаниеТипов, обладающий методом ПривестиЗначение(). Этот метод преобразует переданное значение к заданному типу либо возвращает значение по умолчанию для этого типа, если преобразование невозможно.
Если целевой тип известен в виде строки (например, "Число", "Дата", "Булево", "Строка"), мы можем инициализировать ОписаниеТипов напрямую по имени типа:
Функция ПривестиСтрокуКТипуПоИмени(ЗначениеСтрокой, ИмяТипа)
Описание = Новый ОписаниеТипов(ИмяТипа);
Возврат Описание.ПривестиЗначение(ЗначениеСтрокой);
КонецФункции
Посмотрим на пример пакетной обработки, где проверяется работа метода на разных типах данных:
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Значение");
ТЗ.Колонки.Добавить("Строка");
ТЗ.Колонки.Добавить("Число");
ТЗ.Колонки.Добавить("Булево");
ТЗ.Колонки.Добавить("Дата");
МассивЗначений = Новый Массив();
МассивЗначений.Добавить("1");
МассивЗначений.Добавить("Истина");
МассивЗначений.Добавить("20230101");
Для Каждого ТекЗначение Из МассивЗначений Цикл
Стр = ТЗ.Добавить();
Стр.Значение = ТекЗначение;
Для Каждого Колонка Из ТЗ.Колонки Цикл
КолонкаИмя = Колонка.Имя;
Если КолонкаИмя = "Значение" Тогда
Продолжить;
КонецЕсли;
Описание = Новый ОписаниеТипов(КолонкаИмя);
Стр[КолонкаИмя] = Описание.ПривестиЗначение(ТекЗначение);
КонецЦикла;
КонецЦикла;
Проанализируем распространенную ситуацию: разработчик получает тип из метаданных реквизита, например, через конструкцию РеквизитМетаданных.Тип.Типы()[0]. В этом случае переменная содержит значение с типом Тип, у которого отсутствует собственный метод ПривестиЗначение().
В конструктор ОписаниеТипов можно передавать не только строку с именем типа, но и массив типов или массив строк. Если у нас есть конкретный Тип, правильнее всего поместить его в массив и создать ОписаниеТипов на его основе:
Функция ПривестиСтрокуКТипу(ЗначениеСтрокой, ТребуемыйТип)
МассивТипов = Новый Массив;
МассивТипов.Добавить(ТребуемыйТип);
Описание = Новый ОписаниеТипов(МассивТипов);
Возврат Описание.ПривестиЗначение(ЗначениеСтрокой);
КонецФункции
Также, если мы уже работаем с метаданными конкретного объекта конфигурации (например, заполняем реквизит документа или справочника), нам нет необходимости извлекать массив типов через Типы(). Свойство Реквизит.Тип само по себе уже является готовым объектом ОписаниеТипов:
// МетаданныеРеквизита.Тип уже содержит ОписаниеТипов
ОписаниеРеквизита = Метаданные.Документы.ПоступлениеТоваровУслуг.Реквизиты.НомерВходящегоДокумента.Тип;
ПриведенноеЗначение = ОписаниеРеквизита.ПривестиЗначение(ИсходнаяСтрока);
Выясним важные тонкости поведения платформы при использовании этого метода, чтобы избежать логических ошибок в коде:
ПривестиЗначение() не вызывает исключений (ошибок выполнения), если входная строка повреждена или не соответствует типу. Вместо генерации исключения метод вернет дефолтное пустое значение целевого типа (для числа — 0, для даты — пустую дату '00010101000000', для булево — Ложь). Если для бизнес-логики важно отличать ошибку конвертации от реального нуля, данный метод требует дополнительной валидации строки."ГГГГММДД" (или "ГГГГММДДЧЧММСС"), либо строго соответствует текущим региональным настройкам информационной базы. Нестандартные форматирования дат приведут к получению пустой даты.ПривестиЗначение() из обычной строки вернет пустую ссылку этого типа. Поиск реального объекта в базе данных метод не осуществляет. Для ссылочных типов необходимо обращаться к менеджеру соответствующего объекта (через НайтиПоНаименованию(), НайтиПоКоду() или с помощью запроса).В ходе обсуждений на форумах нередко предлагаются другие варианты, однако они имеют существенные ограничения:
Вычислить(ИмяФункцииПреобразования + "(ИсходноеЗначение)"). Данный способ категорически не рекомендуется для непроверенных входных данных, так как несет прямую угрозу безопасности (уязвимость к инъекциям кода) и жестко зависит от контекста вызова."true", "false", "1" или "0", а для даты — только стандарт ISO ("ГГГГ-ММ-ДД"). Русскоязычные строки "Истина" или привычные даты через точку вызовут аварийную остановку по ошибке разбора XML.Таким образом, для безопасного и универсального приведения типов в 1С наиболее надежным решением остается использование объекта ОписаниеТипов с инициализацией через массив типов или строковое имя типа.