Разработка в среде 1С:Предприятие иногда подбрасывает задачи, которые кажутся мистическими. Представьте ситуацию: при выполнении обработки в составе расширения система выдает ошибку «Поле объекта не обнаружено». Вы открываете подробности, видите конкретную строку кода, вызывающую сбой, копируете её, запускаете глобальный поиск по всей конфигурации и расширениям, но... поиск выдает нулевой результат. В модуле формы или объекта такой строки просто нет. В этой статье мы разберем, почему так происходит, как «вычислить» скрытый код и как правильно переписать такие участки, чтобы не создавать проблем себе и коллегам.
Разберем ситуацию, с которой столкнулся автор темы. Ошибка указывала на строку НовыйСправочник = Номенклатура. Однако в конфигураторе её найти не удавалось. Проблема крылась в использовании встроенной функции Выполнить(). Рассмотрим пример того, как это выглядело в коде:
// Код, который спрятал ошибку
Для Счетчик = 1 По 10 Цикл
Выполнить("НовыйСправочник = Номенклатура" + Счетчик);
КонецЦикла;
Проанализируем, что здесь происходит. Платформа 1С берет строковое выражение, конкатенирует его с числом и пытается исполнить полученный текст как фрагмент программного кода. Для глобального поиска в конфигураторе этот фрагмент — всего лишь текстовая константа, часть которой собирается в рантайме. Именно поэтому стандартные инструменты поиска (Ctrl+Shift+F) бесполезны: они ищут статичный текст, а не результат вычисления выражений.
Когда исполняемый код формируется динамически, он компилируется платформой непосредственно в момент вызова функции Выполнить() или Вычислить(). В журнале регистрации или в окне ошибки вы увидите уже итоговую сформированную строку, но в исходных текстах модулей её не существует в явном виде.
Если вы столкнулись с подобной «невидимой» ошибкой, не стоит пытаться угадать место сбоя. Рассмотрим по шагам методику отладки таких участков:
Поле объекта не обнаружено, отладчик прервет выполнение именно на строке с вызовом Выполнить().Выполнить(ТекстКоманды), выделите переменную ТекстКоманды и через Shift+F9 (Табло) посмотрите её текущее значение. Там вы увидите именно тот текст, который система не смогла исполнить.
ТекстКоманды = "НовыйСправочник = Номенклатура" + Счетчик;
Сообщить(ТекстКоманды); // Мы увидим, что именно пытается сделать система
Выполнить(ТекстКоманды);
В профессиональном сообществе 1С-разработчиков использование Выполнить() без крайней необходимости считается признаком низкого качества кода (так называемым «антипаттерном»). Проанализируем основные причины:
Выполнить() попадут данные, введенные пользователем (например, через поле ввода), это может привести к исполнению произвольного вредоносного кода в контексте сервера.Вместо того чтобы динамически создавать имена переменных типа Номенклатура1, Номенклатура2 и так далее, проанализируем современные подходы 1С. Рассмотрим, как переписать проблемный код с использованием коллекций значений.
Использование структуры или соответствия
Если вам нужно обращаться к значениям по строковому имени, используйте объект Структура. Это позволяет избежать функции Выполнить():
// Вместо динамических переменных используем структуру
ДанныеСправочников = Новый Структура;
Для Счетчик = 1 По 10 Цикл
ИмяКлюча = "Номенклатура" + Счетчик;
// Безопасное присвоение значения
ДанныеСправочников.Вставить(ИмяКлюча, Справочники.Номенклатура.ПустаяСсылка());
КонецЦикла;
// Обращение к значению
ТекущееЗначение = ДанныеСправочников["Номенклатура5"];
Использование массивов
Если важна последовательность объектов, лучше использовать Массив. Это наиболее быстрый и прозрачный способ хранения нумерованных данных:
СписокНоменклатуры = Новый Массив;
Для Счетчик = 1 По 10 Цикл
СписокНоменклатуры.Добавить(НайденнаяНоменклатура);
КонецЦикла;
// Доступ по индексу
НужныйОбъект = СписокНоменклатуры[4]; // Пятый элемент массива
Поскольку обсуждаемая обработка находится в составе расширения, важно помнить о контексте видимости. Если динамический код обращается к объектам, которые есть в основной конфигурации, но не добавлены в расширение, система также может выдать ошибку «Поле объекта не обнаружено». Проанализируем ситуацию: платформа пытается найти объект в пространстве имен расширения, не находит его и генерирует исключение. При использовании Выполнить() в расширениях всегда проверяйте, что все задействованные типы и объекты метаданных явно включены в состав расширения.
Подводя итог, можно сказать: если вы видите ошибку в коде, которого «нет», ищите вызовы Выполнить() или Вычислить(). А еще лучше — избавьтесь от них, заменив на работу со структурами, массивами или соответствиями. Это сделает ваш код надежным, понятным и легким в поддержке.