Разберем одну из распространенных и иногда весьма запутанных ошибок в разработке отчетов на Системе Компоновки Данных (СКД) в 1С:Предприятие – "Значение не является значением объектного типа" при попытке вызова метода ВыгрузитьЗначения(). Эта ошибка часто возникает при получении пользовательских параметров отчета и может привести в замешательство, особенно когда отчет стабильно работает в одной базе, но падает в другой.
Предположим, вы разрабатываете внешний отчет, добавляете в него новое поле, тестируете в тестовой базе – все отлично. Переносите в рабочую базу, запускаете, и тут появляется ошибка: "Значение не является значением объектного типа(ВыгрузитьЗначения)". Рассмотрим подробнее, что это за ошибка, почему она возникает и как ее эффективно диагностировать и устранить.
Метод ВыгрузитьЗначения() в 1С используется для получения содержимого коллекций значений, таких как СписокЗначений, Массив или ТаблицаЗначений, в виде массива или списка для дальнейшей обработки. Когда система выдает ошибку "Значение не является значением объектного типа", это означает, что переменная, на которой вы пытаетесь вызвать этот метод, либо не инициализирована (ее значение Неопределено), либо содержит значение примитивного типа (например, строка, число, дата), которое, очевидно, не имеет метода ВыгрузитьЗначения().
В контексте отчетов СКД, эта ошибка обычно проявляется при попытке получить значения пользовательских параметров. Давайте посмотрим на типовой фрагмент кода, где может возникнуть такая проблема:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// ...
ПараметрыЗапроса = Новый Структура("ПоставГамбург,Постав6Проц,ОсновКлиенты");
Для Каждого ЭлмПарам Из ПараметрыЗапроса Цикл
ПарамСКД = ПолучитьПользовательскийПараметр(ЭлмПарам.Ключ, КомпоновщикНастроек);
Если ЭлмПарам.Ключ="ОсновКлиенты" или ЭлмПарам.Ключ="Постав6Проц" Тогда
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ПарамСКД.Значение.ВыгрузитьЗначения); // <-- ОШИБКА ЗДЕСЬ
Иначе
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ПарамСКД.Значение);
КонецЕсли;
КонецЦикла;
// ...
КонецПроцедуры
В этом коде ошибка возникает в строке ПарамСКД.Значение.ВыгрузитьЗначения;. Это происходит потому, что ПарамСКД.Значение в этот момент не является объектом, поддерживающим метод ВыгрузитьЗначения. Чаще всего это случается по одной из следующих причин:
ПолучитьПользовательскийПараметр() возвращает объект, у которого свойство Значение равно Неопределено.Строка), но код ожидает, что он будет СписокЗначений или аналогичной коллекцией. Если пользователь выбрал только одно значение для параметра, который *может* быть списком, ПарамСКД.Значение может содержать не СписокЗначений, а само это единственное значение, и тогда ВыгрузитьЗначения() будет неприменимо.ПолучитьПользовательскийПараметр() возвращает Неопределено.Неопределено или имеют некорректный тип, поскольку новая логика работы с ними еще не применена. В случае, описанном в исходной теме, именно кэширование оказалось главной причиной проблемы.Первый шаг к решению проблемы – это понять, какое именно значение является "не объектным".
Если отладка работает корректно, установите точку останова прямо перед строкой, вызывающей ошибку:
Если ЭлмПарам.Ключ="ОсновКлиенты" или ЭлмПарам.Ключ="Постав6Проц" Тогда
// Установите точку останова здесь
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ПарамСКД.Значение.ВыгрузитьЗначения);
// ...
Затем, во время выполнения, посмотрите значения ЭлмПарам.Ключ, ПарамСКД и, самое главное, ПарамСКД.Значение. Вы увидите, что ПарамСКД.Значение, скорее всего, будет Неопределено или каким-то примитивным типом (например, Строка, если пользователь выбрал один элемент из списка, а не сам СписокЗначений).
Если отладка по какой-то причине не работает (что часто бывает с внешними отчетами или на сервере), воспользуйтесь функцией Сообщить():
Если ЭлмПарам.Ключ="ОсновКлиенты" или ЭлмПарам.Ключ="Постав6Проц" Тогда
Сообщить("Ключ параметра: " + ЭлмПарам.Ключ);
Сообщить("Тип значения параметра: " + ТипЗнч(ПарамСКД.Значение));
Сообщить("Значение параметра: " + Строка(ПарамСКД.Значение)); // Строка() для преобразования
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ПарамСКД.Значение.ВыгрузитьЗначения);
// ...
Это поможет нам выяснить, какой именно параметр вызывает проблему и какое значение он имеет.
В исходной теме пользователь столкнулся с тем, что точки останова не срабатывают. Это очень частая проблема при отладке внешних отчетов, особенно если они выполняются на сервере 1С:Предприятия. Рассмотрим, почему это происходит и как настроить отладку.
Почему не срабатывает точка останова?
Внешние отчеты, особенно те, что используют СКД, могут выполняться как на клиенте, так и на сервере. Если отчет запускается на сервере (например, в тонком клиенте, веб-клиенте, или как фоновое задание), то для отладки его серверного кода необходимо, чтобы отладка сервера 1С была настроена и активна.
Настройка отладки серверного кода:
-debug. Этот ключ разрешает серверу принимать соединения от отладчиков.
ragent.exe или rmngr.exe). Добавьте ключ -debug к параметрам запуска службы. Например, путь может выглядеть так: "C:\Program Files\1cv8\8.3.ХХ.ХХХХ\bin\ragent.exe" -debug.После этих настроек точки останова в серверном коде вашего отчета должны начать срабатывать, позволяя нам увидеть реальные значения переменных и точно определить источник ошибки.
Теперь, когда мы понимаем причины и методы диагностики, давайте рассмотрим, как решить проблему "Значение не является значением объектного типа(ВыгрузитьЗначения)".
Как показал опыт автора темы, одной из самых коварных причин является кэширование 1С. Система может продолжать использовать старую версию отчета, даже если вы загрузили новую. Это приводит к тому, что изменения в коде не применяются, а параметры могут быть Неопределено или иметь некорректный тип, как будто они не были установлены в старой версии отчета.
Если отчет встроен в конфигурацию, но вы его дорабатываете как внешний, после доработки его можно временно переименовать или добавить цифры в имя. Если же это внешний файл (.erf), просто сохраните его под новым именем.
%APPDATA%\1C\1CE\.После очистки кэша и повторного запуска 1С, система будет вынуждена загрузить все компоненты заново, что часто решает проблемы, связанные с устаревшими версиями файлов.
Даже если проблема с кэшированием решена, крайне важно писать надежный код, который устойчив к неопределенным или некорректным значениям параметров.
Неопределено и тип данных: Всегда проверяйте, что полученное значение параметра не является Неопределено и имеет ожидаемый тип, прежде чем вызывать специфические методы.ЗначениеЗаполнено(): Эта функция может быть полезна для проверки, содержит ли параметр хоть какое-то значимое значение.Давайте улучшим наш код с учетом этих проверок:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ПараметрыЗапроса = Новый Структура("ПоставГамбург,Постав6Проц,ОсновКлиенты");
Для Каждого ЭлмПарам Из ПараметрыЗапроса Цикл
ПарамСКД = ПолучитьПользовательскийПараметр(ЭлмПарам.Ключ, КомпоновщикНастроек);
Если ПарамСКД = Неопределено Тогда // Проверяем, что параметр вообще существует
Сообщить("Внимание: Параметр '" + ЭлмПарам.Ключ + "' не найден в настройках компоновщика.");
Продолжить;
КонецЕсли;
ЗначениеПараметра = ПарамСКД.Значение;
Если ЭлмПарам.Ключ="ОсновКлиенты" или ЭлмПарам.Ключ="Постав6Проц" Тогда
Если ЗначениеПараметра = Неопределено Тогда
Сообщить("Внимание: Для параметра '" + ЭлмПарам.Ключ + "' не выбрано значение. Использование пустого списка.");
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, Новый Массив); // Вставляем пустой массив или список по умолчанию
ИначеЕсли ТипЗнч(ЗначениеПараметра) = Тип("СписокЗначений") Тогда
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ЗначениеПараметра.ВыгрузитьЗначения());
ИначеЕсли ТипЗнч(ЗначениеПараметра) = Тип("Массив") Тогда // Если уже массив
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ЗначениеПараметра);
Иначе // Если это одно значение, а не список/массив
Сообщить("Внимание: Для параметра '" + ЭлмПарам.Ключ + "' выбрано одно значение. Преобразуем в массив.");
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, Новый Массив({ЗначениеПараметра}));
КонецЕсли;
Иначе
ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ЗначениеПараметра);
КонецЕсли;
КонецЦикла;
ПарамСКД = ПолучитьПользовательскийПараметр("ПериодОтчета", КомпоновщикНастроек);
Если ПарамСКД <> Неопределено И ЗначениеЗаполнено(ПарамСКД.Значение) И ТипЗнч(ПарамСКД.Значение) = Тип("СтандартныйПериод") Тогда
ПараметрыЗапроса.Вставить("Д1", ПарамСКД.Значение.ДатаНачала);
ПараметрыЗапроса.Вставить("Д2", ПарамСКД.Значение.ДатаОкончания);
ПараметрыЗапроса.Вставить("Гран1", Новый Граница(ПарамСКД.Значение.ДатаНачала, ВидГраницы.Включая));
ПараметрыЗапроса.Вставить("Гран2", Новый Граница(ПарамСКД.Значение.ДатаОкончания, ВидГраницы.Включая));
Иначе
// Обработка случая, если период не установлен или неверного типа
Сообщить("Внимание: Параметр 'ПериодОтчета' не установлен или имеет неверный тип.");
// Можно установить значения по умолчанию или прервать формирование отчета
КонецЕсли;
ПараметрыЗапроса.Вставить("ЭлмПланАДМ", Справочники.Номенклатура.НайтиПоКоду("00-00017779",Ложь));
СписокОшибок = Неопределено;
МояТаблица = ПолучитьДопТЗ(ПараметрыЗапроса, СписокОшибок);
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТЗ", МояТаблица);
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки,ВнешниеНаборыДанных,ДанныеРасшифровки);
ДокументРезультат.Очистить;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
ДокументРезультат.ПоказатьУровеньГруппировокСтрок(1);
Если НЕ СписокОшибок=Неопределено Тогда
ОбщегоНазначенияКлиентСервер.СообщитьОшибкиПользователю(СписокОшибок);
КонецЕсли;
КонецПроцедуры
В этом улучшенном коде мы:
ПарамСКД не является Неопределено, прежде чем обращаться к его свойству Значение.ЗначениеПараметра не является Неопределено.ТипЗнч(), чтобы убедиться, что ЗначениеПараметра является СписокЗначений (или Массив), прежде чем вызывать ВыгрузитьЗначения().СтандартныйПериод, проверяя его наличие и тип перед использованием полей ДатаНачала и ДатаОкончания.Убедитесь, что параметры в самой СКД настроены корректно:
СписокЗначений), установите флажок "Список значений" в свойствах параметра. Это позволит пользователю выбирать несколько значений в форме отчета, и система корректно передаст их как СписокЗначений.СправочникСсылка.Номенклатура, СтандартныйПериод и т.д.).Ошибка "Значение не является значением объектного типа(ВыгрузитьЗначения)" является частым спутником разработчиков 1С, работающих с отчетами СКД. Как мы выяснили, причиной может быть как некорректная обработка параметров в коде, так и скрытые механизмы кэширования 1С. Мы рассмотрели:
ВыгрузитьЗначения().Неопределено и тип данных.Применяя эти шаги, вы сможете не только устранить текущую ошибку, но и повысить стабильность и отлаживаемость ваших внешних отчетов в 1С:Предприятии. Для более глубокого изучения программного формирования отчетов и управления компоновкой можно использовать примеры программной работы с СКД.