При написании или доработке программного кода на платформе 1С:Предприятие разработчики нередко сталкиваются с исключением: «Ошибка при вызове метода контекста (ЗначениеЗаполнено): Проверка мутабельных значений на заполненность не поддерживается». Давайте подробно разберем, почему возникает данное исключение, какие типы данных платформа считает мутабельными и как правильно переписать проверку в зависимости от решаемой прикладной задачи.
Проанализируем типовую ситуацию из практики. В коде общего модуля выполняется условие:
Если ЗначениеЗаполнено(ОперацияЗБ) Тогда
// Выполнение алгоритма
КонецЕсли;
Если в переменную ОперацияЗБ вместо ссылки передается сам прикладной объект (например, ДокументОбъект или СправочникОбъект), платформа немедленно прерывает выполнение с указанной ошибкой. Выясним причину такого поведения системы.
Функция ЗначениеЗаполнено() предназначена исключительно для работы с неизменяемыми (иммутабельными) типами и примитивными значениями. К ним относятся:
Число, Строка, Дата, Булево, УникальныйИдентификатор.Неопределено, Null.ДокументСсылка.*, СправочникСсылка.*, ПеречислениеСсылка.*, ПланВидовХарактеристикСсылка.* и другие.Мутабельными (изменяемыми) называются типы данных, внутреннее состояние которых может динамически модифицироваться в процессе работы программы. Платформа 1С принципиально не может однозначно определить критерий «заполненности» сложного составного объекта, поскольку в нем могут присутствовать десятки реквизитов и табличных частей. К мутабельным типам относятся:
ДокументОбъект.*, СправочникОбъект.*, ПланВидовХарактеристикОбъект.*, ОбработкаОбъект.* и т. д.Массив, Структура, Соответствие, ТаблицаЗначений, ДеревоЗначений, СписокЗначений.Попытка передать любой из перечисленных выше типов напрямую в метод ЗначениеЗаполнено() всегда вызывает исключение. Рассмотрим рабочие способы исправления ошибки.
Если в алгоритме требуется лишь убедиться, что переменная содержит переданный объект, а не является пустым значением Неопределено или Null, заменим вызов функции на прямое сравнение:
Если ОперацияЗБ <> Неопределено И ОперацияЗБ <> Null Тогда
// Объект передан в переменную и доступен для работы
КонецЕсли;
Если в переменной находится прикладной объект данных (например, ДокументОбъект), мы можем проверить его реквизит Ссылка. Сама ссылка является иммутабельным значением, поэтому метод ЗначениеЗаполнено() отработает корректно:
Если ОперацияЗБ <> Неопределено И ЗначениеЗаполнено(ОперацияЗБ.Ссылка) Тогда
// Ссылка объекта не является пустой
КонецЕсли;
Посмотрим на важный нюанс: если объект был только что создан в памяти с помощью метода СоздатьДокумент() и еще ни разу не записывался в базу данных, его ссылка может быть пустой (или не инициализированной). Учитывайте этот момент в логике расчета.
Когда требуется выяснить, записан ли переданный объект данных в информационную базу или он является абсолютно новым (созданным в оперативной памяти), используем встроенный метод объекта ЭтоНовый():
Если ОперацияЗБ <> Неопределено Тогда
Если Не ОперацияЗБ.ЭтоНовый() Тогда
// Документ уже существует и сохранен в базе данных
КонецЕсли;
КонецЕсли;
Разберем ситуацию, когда в одну и ту же процедуру из разных мест конфигурации может приходить как ссылка (ДокументСсылка), так и сам объект (ДокументОбъект), либо значение Неопределено. В таком случае напишем универсальную проверку через свойство Ссылка или анализ типа:
Если ОперацияЗБ <> Неопределено И ОперацияЗБ <> Null Тогда
СсылкаДляПроверки = Неопределено;
// Проверяем, передана ссылка или объект
Если ОбщегоНазначенияКлиентСервер.ЭтоСсылка(ТипЗнч(ОперацияЗБ)) Тогда
СсылкаДляПроверки = ОперацияЗБ;
ИначеЕсли ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(ОперацияЗБ, "Ссылка") Тогда
СсылкаДляПроверки = ОперацияЗБ.Ссылка;
КонецЕсли;
Если ЗначениеЗаполнено(СсылкаДляПроверки) Тогда
// Обработка данных
КонецЕсли;
КонецЕсли;
Если функции БСП недоступны, проверим тип стандартными средствами платформы:
ТипЗначения = ТипЗнч(ОперацияЗБ);
Если Документы.ТипВсеСсылки().СодержитТип(ТипЗначения) Тогда
Заполнено = ЗначениеЗаполнено(ОперацияЗБ);
ИначеЕсли ОперацияЗБ <> Неопределено И ОперацияЗБ <> Null Тогда
Заполнено = ЗначениеЗаполнено(ОперацияЗБ.Ссылка);
Иначе
Заполнено = Ложь;
КонецЕсли;
Если в переменную ошибочно передается универсальная коллекция (например, Массив, ТаблицаЗначений, Структура), проверку на заполненность выполняем через метод Количество():
// Для массивов, таблиц значений и списков
Если ПеременнаяКоллекция <> Неопределено И ПеременнаяКоллекция.Количество() > 0 Тогда
// В коллекции есть элементы
КонецЕсли;
Таким образом, для исправления ошибки достаточно определить, какого типа значение находится в проверяемой переменной, и заменить неподдерживаемый вызов ЗначениеЗаполнено() на проверку ссылки, метода ЭтоНовый() или количества элементов.