При разработке во внешних обработках или отчетах на платформе «1С:Предприятие» программисты часто сталкиваются с досадными ошибками компиляции или выполнения. Одна из самых распространенных ошибок среди начинающих разработчиков — «Обращение к процедуре объекта как к функции» при вызове метода Выполнить(). В этой статье мы подробно разберем, почему возникает эта проблема, чем отличаются похожие методы у разных объектов и как правильно написать код, чтобы избежать подобных коллизий.
Для начала проанализируем базовый синтаксис встроенного языка 1С. Платформа жестко разграничивает два типа методов:
Возврат). Вызов функции можно присваивать переменным, использовать в выражениях или передавать в качестве параметров другим методам.Обращение к процедуре объекта как к функции.Когда мы пишем код вида Переменная = Объект.Метод();, компилятор 1С ожидает, что Метод() является функцией. Если на самом деле этот метод определен в платформе как процедура, система выдаст ошибку и прекратит выполнение программы.
Основная причина путаницы заключается в том, что разработчики привыкают к работе со стандартным объектом Запрос. Давайте сравним поведение метода Выполнить() у двух разных объектов платформы.
Рассмотрим стандартный объект Запрос. У него метод Выполнить() спроектирован как функция. Данный метод возвращает объект типа РезультатЗапроса. Поэтому следующий код абсолютно корректен и используется повсеместно:
// Корректный код для обычного запроса
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура";
РезультатЗапроса = Запрос.Выполнить(); // Здесь Выполнить() работает как ФУНКЦИЯ
Теперь рассмотрим объект ПостроительЗапроса. Этот объект предназначен для динамического конструирования запросов, настройки отборов и порядков. Разработчики платформы спроектировали метод Выполнить() у объекта ПостроительЗапроса (а также у смежного объекта ПостроительОтчета) как процедуру. Она запускает построение запроса, обрабатывает внутренние механизмы и сохраняет полученные данные во внутреннем свойстве Результат самого построителя.
Попытка вызвать его аналогично стандартному запросу неизбежно приведет к ошибке:
// НЕКОРРЕКТНЫЙ КОД - вызовет ошибку компиляции!
РезультатЗапроса = ПостроительЗапроса.Выполнить();
Разберем по шагам, как исправить эту ошибку в коде вашей внешней обработки. Для того чтобы успешно выполнить запрос с помощью построителя и получить его результаты, необходимо разделить процесс на два этапа: сначала вызвать процедуру исполнения, а затем обратиться к свойству, содержащему результат.
Правильный шаблон кода выглядит следующим образом:
// Шаг 1: Инициализируем построитель запроса и задаем текст
ПостроительЗапроса = Новый ПостроительЗапроса;
ПостроительЗапроса.Текст = "ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура";
// Шаг 2: Вызываем процедуру выполнения (без присваивания переменной!)
ПостроительЗапроса.Выполнить();
// Шаг 3: Получаем результат из свойства "Результат" и записываем его в переменную
РезультатЗапроса = ПостроительЗапроса.Результат;
// Шаг 4: Выгружаем данные или обходим выборку
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка данных
КонецЦикла;
Именно такое решение позволяет обойти ограничение платформы и корректно получить данные для дальнейшей работы.
Чтобы закрепить материал, рассмотрим подробнее другие типичные ситуации, в которых разработчики часто совершают аналогичную синтаксическую ошибку:
УстановитьПараметр() объекта Запрос является процедурой. Код Рез = Запрос.УстановитьПараметр("Склад", Склад); вызовет ошибку. Правильно писать просто: Запрос.УстановитьПараметр("Склад", Склад);.Прочитать() или Открыть() у объекта ТекстовыйДокумент являются процедурами. Они не возвращают статус успешности операции. Их нужно вызывать как самостоятельные инструкции.ЗаполнитьЗначения() у объекта ТаблицаЗначений служит для группового изменения данных в колонке и не возвращает измененную таблицу. Вызов НоваяТаблица = Таблица.ЗаполнитьЗначения(Истина, "Флаг"); приведет к ошибке.Элементы.ИмяТаблицы.ДобавитьСтроку() является процедурой (интерфейсным действием). Если вам нужно программно добавить строку в данные и получить ссылку на нее, используйте метод коллекции данных: НоваяСтрока = Объект.ИмяТаблицы.Добавить();.Проанализируем сопутствующие объекты платформы. Очень часто разработчики путают ПостроительЗапроса и ПостроительОтчета, так как оба они содержат схожие методы и свойства, включая процедуру Выполнить(). Однако между ними есть принципиальная разница в области применения:
ПостроительЗапроса — это невизуальный (серверный) объект. Он оптимизирован для работы с базами данных, формирования динамических текстов запросов и наложения условий. Его можно абсолютно безопасно использовать в фоновых заданиях, на стороне сервера и во внешних соединениях.ПостроительОтчета — ориентирован на клиентское представление данных. Его основная задача — не просто получить результат, но и красиво вывести его в табличный документ с группировками и оформлением. Данный объект имеет ограничения при использовании на стороне сервера (особенно в веб-клиенте или тонком клиенте) и считается более тяжеловесным.В заключение отметим важный нюанс, касающийся современных стандартов разработки. Семейство объектов класса «Построитель...» активно развивалось в версиях платформы 1С 8.0 и 8.1. В современных конфигурациях на платформе 1С 8.3 (таких как ERP 2, Управление торговлей 11, Бухгалтерия предприятия 3.0) эти технологии признаны устаревшими (legacy).
Сегодня для разработки гибких отчетов, динамического построения запросов и реализации сложных условий отбора применяется СКД (Система компоновки данных). Использование построителей в новом коде не рекомендуется по следующим причинам:
Тем не менее при поддержке старого кода или доработке нетиповых конфигураций знание особенностей работы с ПостроительЗапроса и понимание разницы между процедурами и функциями сбережет вам массу времени и сил.