В процессе разработки на платформе 1С 7.7, особенно при использовании расширения 1С++ и технологии объектно-ориентированного программирования (КОП), часто возникает задача десериализации данных. Например, когда мы читаем XML-файл, мы получаем имя атрибута и его значение в виде строк. Стандартный подход с использованием условий Если...Тогда для каждого свойства быстро превращается в громоздкий и трудноподдерживаемый код («портянку»).
В этой статье мы разберем, как уйти от ручного перебора свойств и реализовать универсальный механизм установки значений по их строковому имени, используя возможности 1С++ и штатные функции платформы.
Самый простой, но имеющий свои ограничения способ — это использование функции Шаблон(). Этот метод позволяет исполнить фрагмент кода, переданный в виде строки. Однако в 1С 7.7 функция Шаблон предназначена для вычисления выражений, а не для прямого присваивания. Чтобы обойти это ограничение, мы создадим вспомогательную функцию-посредник.
Проанализируем пример реализации:
// Вспомогательная функция, которая выполняет присваивание
Функция УстАтрибут(пАтр, пЗн)
пАтр = пЗн;
Возврат ""; // Возвращаем пустую строку, чтобы Шаблон ничего не вывел
КонецФункции
// Основная процедура установки
Процедура УстановитьСвойствоКОП(пОбъект, пСвойство, пЗначение)
// Формируем строку кода для выполнения
Шаблон("[УстАтрибут(" + пОбъект + "." + пСвойство + ", пЗначение)]");
КонецПроцедуры
Важные нюансы:
ЗначениеВСтрокуВнутр и ЗначениеИзСтрокиВнутр, что существенно снизит производительность.Экспорт, иначе контекст функции Шаблон их не увидит.Более мощный и профессиональный способ — использование объекта ВыполняемыйМодуль из состава 1С++. Он позволяет компилировать и выполнять произвольный код в контексте вашего объекта. Это работает быстрее и стабильнее, чем Шаблон.
Рассмотрим, как правильно организовать этот процесс внутри класса:
Перем ВМ; // Объект "ВыполняемыйМодуль"
Перем Свойство1 Экспорт;
Перем Свойство2 Экспорт;
Процедура Конструктор()
// Инициализируем модуль и привязываем его к текущему контексту объекта
ВМ = СоздатьОбъект("ВыполняемыйМодуль");
ВМ.НазначитьКонтекст(Я());
КонецПроцедуры
Процедура УстановитьСвойство(ИмяПеременной, Значение) Экспорт
// Формируем текст временной процедуры
ТекстМодуля = "
|Процедура ВыполнитьУстановку(Значение)
| " + ИмяПеременной + " = Значение;
|КонецПроцедуры
|";
// Компилируем и запускаем
ВМ.УстановитьМодуль(ТекстМодуля);
ВМ.КомпилироватьИВыполнитьМодуль();
ВМ.ВыполнитьУстановку(Значение);
КонецПроцедуры
Разберем по шагам, что здесь происходит. Мы создаем объект ВыполняемыйМодуль, который «знает» о контексте нашего класса (благодаря методу НазначитьКонтекст(Я())). При вызове установки мы динамически генерируем текст процедуры, где имя переменной подставляется прямо в код присваивания. Это позволяет работать с любыми типами данных без потери производительности на преобразование в строки.
Совет по оптимизации: Чтобы не перекомпилировать модуль при каждом вызове (что довольно затратно), можно один раз создать универсальную процедуру-диспетчер или использовать кэширование скомпилированных модулей.
Если ваша задача — хранить произвольный набор данных из XML, рассмотрите использование динамических свойств. Вместо того чтобы описывать каждую переменную через Перем, вы можете перехватывать обращения к свойствам.
Проанализируем алгоритм работы через предопределенные методы класса:
Структура (или ИндексированнаяТаблица).ПриЗаписиДинамическогоСвойства(Имя, Значение).Это самый «красивый» способ с точки зрения архитектуры, так как он не требует динамической компиляции кода вообще. Объект будет «поглощать» любые атрибуты из XML, сохраняя их во внутренней коллекции.
Если вы сами управляете форматом сохранения, то 1С++ предлагает встроенные механизмы сериализации. Для этого в классе определяются специальные функции, которые позволяют платформе автоматически упаковывать и распаковывать состояние объекта.
Пример функций для поддержки сериализации:
Функция КлассСохраняемый()
Возврат 1; // Указываем, что класс поддерживает сериализацию
КонецФункции
Функция СохранитьКлассВСтроку()
// Здесь можно использовать ЗначениеВСтрокуВнутр для внутренней структуры
Возврат ЗначениеВСтроку(ВажныеЗначения);
КонецФункции
Процедура ЗагрузитьИзСтроки(СтрДанных)
// Восстанавливаем данные
ВажныеЗначения = ЗначениеИзСтроки(СтрДанных);
КонецПроцедуры
Хотя автор вопроса упоминал необходимость работы именно с XML для внешних систем, данный метод полезен для внутреннего обмена данными между объектами 1С 7.7.
При получении данных из XML-атрибута мы всегда имеем дело со строкой. Выясним причину, почему простая установка значения может не сработать. Если свойство объекта в 1С должно быть числом или датой, простое присваивание строки может привести к ошибкам в дальнейших расчетах.
Для решения этой проблемы рекомендуется:
чЦена, дДата. При десериализации анализировать первый символ имени и выполнять Число() или Дата().ИнфоОКлассе из 1С++, чтобы программно определить список доступных свойств и их типов перед установкой.Резюме: Для разовых и простых задач подойдет метод с Шаблон(). Для массовой загрузки данных и сложных систем лучшим выбором будет ВыполняемыйМодуль или архитектура с динамическими свойствами через Структуру. Эти подходы позволяют сделать код десериализации XML лаконичным, состоящим всего из нескольких строк цикла по атрибутам узла.