При работе с электронным документооборотом (ЭДО), особенно в интеграционных решениях с системой Диадок, разработчики часто сталкиваются с крайне странной ошибкой: Несоответствие типов XDTO: Тип '{URI}ИмяТипа' не соответствует типу '{URI}ИмяТипа'. На первый взгляд сообщение кажется абсурдным, ведь платформа утверждает, что тип не соответствует самому себе. Однако в мире 1С и XDTO за этим скрывается глубокая логика работы с фабриками и пространствами имен.
В этой статье мы подробно разберем, почему возникает эта ошибка, как проанализировать контекст выполнения кода и какие способы решения существуют для исправления этой ситуации в конфигурациях 1С.
Основная причина, по которой 1С выдает ошибку «Тип А не соответствует типу А», заключается в том, что платформа сравнивает не только строковое имя типа и его URI (пространство имен), но и саму Фабрику XDTO, в контексте которой был создан объект. В оперативной памяти 1С может одновременно существовать несколько фабрик, содержащих идентичные наборы схем (например, схемы ФНС для счетов-фактур ON_NSCHFDOPPR).
Проанализируем типичную ситуацию: у вас есть корневой объект (например, УПД), который был создан внешней библиотекой или загружен из файла с использованием локальной фабрики. Затем вы пытаетесь программно создать дочерний объект (например, ТекстИнфТип) через глобальную фабрику ФабрикаXDTO или другую фабрику, созданную вручную. Несмотря на то, что описания типов в этих фабриках идентичны, для платформы это разные объекты метаданных. Попытка вставить объект из одной фабрики в свойство объекта из другой фабрики неминуемо приведет к исключению.
Рассмотрим фрагмент кода, который часто становится источником проблем при копировании из типовых обработок:
// Ошибка часто возникает здесь
ТекстИнф = Фабрика.Создать(Фабрика.Тип(ИмяПакетаXDTO, "ТекстИнфТип"));
ТекстИнф.Значен = InfoFileId;
ТекстИнф.Идентиф = "ID";
Попытка
ИнфПолФХЖ1.ТекстИнф.Добавить(ТекстИнф); // Ошибка: Несоответствие типов
Исключение
// Обработка ошибки
КонецПопытки;
В данном примере переменная Фабрика может указывать на глобальную фабрику конфигурации, в то время как объект ИнфПолФХЖ1 был порожден от другой фабрики, инициализированной внутри модуля Диадока (так называемые «матрешки» в коде интеграции). Выясним, как сделать код универсальным и устойчивым к смене контекста.
Самый надежный способ избежать конфликта фабрик — это не создавать объект отдельно, а позволить коллекции родительского объекта самой породить нужный элемент. Если свойство является списковым (максимальное количество появлений больше 1), метод Добавить() у объекта СписокXDTO умеет создавать пустой объект правильного типа в контексте «своей» фабрики.
Проанализируем исправленный код:
// Вместо создания через внешнюю фабрику, используем метод Добавить()
НовыйТекстИнф = ИнфПолФХЖ1.ТекстИнф.Добавить();
// Теперь НовыйТекстИнф ГАРАНТИРОВАННО имеет тот же тип, что и коллекция
НовыйТекстИнф.Значен = InfoFileId;
НовыйТекстИнф.Идентиф = "ID";
Этот подход исключает необходимость указывать URI пространства имен или искать нужную фабрику вручную. Платформа сама определит тип на основе метаданных свойства ТекстИнф.
Если вам необходимо сначала заполнить объект, а только потом добавить его в коллекцию (или если свойство не является списковым), рекомендуется получать тип непосредственно из родительского объекта. Рассмотрим, как это сделать программно:
// Получаем определение свойства из родительского объекта
СвойствоТекстИнф = ИнфПолФХЖ1.Свойства().Получить("ТекстИнф");
// Получаем точный тип, который ожидает это свойство
ТипОбъекта = СвойствоТекстИнф.Тип;
// Создаем объект через фабрику, которой принадлежит этот тип
НовыйОбъект = Фабрика.Создать(ТипОбъекта);
НовыйОбъект.Значен = InfoFileId;
// Теперь добавление пройдет без ошибок
ИнфПолФХЖ1.ТекстИнф.Добавить(НовыйОбъект);
Важный момент: Обратите внимание, что в методе Фабрика.Создать() мы передаем именно объект типа ТипXDTO, полученный из метаданных, а не строковое имя. Это гарантирует совпадение контекста фабрики.
В сообщениях форума упоминалось, что код Диадока представляет собой сложную структуру («матрешки»). Это связано с тем, что разработчики Диадока часто используют динамическую загрузку схем XSD из макетов обработки.
Выясним, почему «тупой копипаст» не всегда работает:
СоздатьФабрикуXDTO(МассивПутейКФайламXSD). Объекты этой фабрики несовместимы с объектами глобальной фабрики 1С.Если вы столкнулись с этой ошибкой, выполните следующие действия в отладчике:
Добавить() или присваивание свойства.ВашОбъект.Тип().ПространствоИмен.Родитель.Свойства().Получить("ИмяСвойства").Тип.ПространствоИмен.Используя приведенные выше методы (создание через Добавить() или получение типа через родительское свойство), вы сделаете свой код устойчивым к изменениям в структуре пакетов XDTO и особенностям реализации внешних интеграционных модулей. Помните, что в XDTO важна не только структура данных, но и строгое соответствие метаданных контексту их создания.