Многие разработчики, имеющие опыт работы с языками программирования вроде C#, Java или JavaScript, часто стремятся перенести привычку «цепочечного» вызова методов (method chaining) в среду 1С. В этих языках вполне естественно написать конструкцию, которая создает объект и тут же вызывает его метод. Однако во встроенном языке 1С попытка написать Результат = (Новый Запрос(Текст)).Выполнить(); приведет к синтаксической ошибке. В этой статье мы подробно разберем, почему это происходит, какие ограничения накладывает платформа и какими способами можно добиться желаемого результата для упрощения кода или быстрой отладки.
Для начала выясним причину, по которой привычный подход не работает. В системе 1С:Предприятие 8 оператор Новый не является функцией в строгом понимании этого слова. Это именно оператор создания экземпляра типа. Грамматика встроенного языка построена таким образом, что операция разыменования (обращение к свойствам и методам через точку) может быть применена только к переменным, результатам функций или результатам других операций разыменования.
Рассмотрим стандартную ситуацию. Согласно документации «Руководство разработчика», при работе с оператором Новый (как в конструкторной, так и в функциональной форме) нельзя ставить точку непосредственно после закрывающей скобки конструктора. Платформа ожидает, что созданный объект сначала будет помещен в какую-либо переменную (стек), и только потом к этой переменной будет применено обращение. Таким образом, следующий код является синтаксически некорректным:
// ОШИБКА: Ожидается символ ';'
Результат = (Новый Запрос("ВЫБРАТЬ 1")).Выполнить();
Даже использование дополнительных скобок не помогает «обмануть» лексический анализатор 1С, так как он не видит в выражении (Новый ...) объекта, готового к немедленному использованию методов через точку.
Разберем подробнее так называемую «функциональную форму» оператора, о которой часто упоминают в документации. Она выглядит следующим образом: Новый(Тип, Параметры). Проанализируем пример, где мы пытаемся создать объект, используя тип как объект метаданных или строку:
// Использование функциональной формы
МассивПараметров = Новый Массив;
МассивПараметров.Добавить("ВЫБРАТЬ 0");
Запрос = Новый("Запрос", МассивПараметров);
// Здесь точка после скобки также недопустима
Важный технический нюанс: если конструктор объекта принимает только один параметр (например, текст запроса), то в функцию Новый() можно передать само значение. Если же параметров несколько, их необходимо упаковать в Массив. Однако, как бы мы ни вызывали Новый, правило остается прежним: результат должен быть сначала присвоен переменной.
Если ваша задача — быстро посмотреть результат выражения в отладчике (Shift + F9) или выполнить динамический код без создания лишних переменных в модуле, можно воспользоваться функцией Вычислить(). Рассмотрим пример, который позволяет получить таблицу значений из запроса в одну строку:
Результат = Вычислить("Новый Запрос(""ВЫБРАТЬ КОНЕЦПЕРИОДА(ДАТАВРЕМЯ(2020, 2, 29), МЕСЯЦ)"")").Выполнить().Выгрузить();
В данном случае функция Вычислить() принимает строку, интерпретирует её и возвращает объект в контекст выражения. Поскольку Вычислить() — это полноценная функция, система позволяет «прицепить» к её результату вызов методов через точку. Это отличный способ для использования в окне «Вычислить выражение», но мы крайне не рекомендуем использовать этот метод в промышленном коде (Production) по следующим причинам:
Для тех, кто хочет писать элегантный и лаконичный код в рабочих модулях, существует профессиональный способ обхода ограничения — использование вспомогательных функций в общих модулях. Посмотрим на примере, как это реализовано в некоторых библиотеках, включая БСП.
Создадим в общем модуле (например, ОбщегоНазначения) простую функцию-«эхо»:
Функция ВернутьОбъект(Объект) Экспорт
Возврат Объект;
КонецФункции
Теперь мы можем использовать эту функцию для создания «цепочки» вызовов. Рассмотрим, как изменится наш код:
Текст = "ВЫБРАТЬ 1 КАК Поле";
ТЗ = ОбщегоНазначения.ВернутьОбъект(Новый Запрос(Текст)).Выполнить().Выгрузить();
Проанализируем ситуацию: функция ВернутьОбъект принимает свежесозданный объект Запрос и возвращает его же. С точки зрения синтаксиса 1С, результатом выполнения функции является объект, к которому можно обращаться через точку. Это позволяет избавиться от промежуточных переменных, если они вам действительно не нужны.
Интересно заметить, что при работе через COM-соединение (например, с другой базой 1С) подобные ограничения отсутствуют. Выясним почему. Рассмотрим пример:
// Работа через COM
КомЗапрос = Соединение.NewObject("Запрос", ТекстЗапроса);
Результат = КомЗапрос.Execute().Unload(); // Здесь цепочка работает!
Причина в том, что NewObject для внешней программы — это обычный метод COM-объекта Соединение. Он возвращает ссылку на объект, и вызывающая среда может свободно обращаться к методам этой ссылки. Внутри же «родного» кода 1С разработчики платформы сознательно ограничили использование точки после Новый для упрощения работы стека вызовов и оптимизации управления памятью на уровне ядра.
Подведем итог нашему исследованию. Использовать оператор Новый внутри выражения с последующим вызовом метода через точку напрямую невозможно. Однако в зависимости от ваших целей можно выбрать один из двух путей:
Вычислить("Новый ..."). Это позволит мгновенно увидеть результат в табло отладчика без модификации рабочего кода.Тем не менее, стоит помнить о «философии» программирования на 1С. Читаемость кода и возможность быстро разобраться в нем другими разработчиками зачастую важнее, чем экономия нескольких строк. Стандартное написание с явным созданием переменной Запрос делает код понятным, упрощает установку параметров и отладку каждого шага выполнения.