К статье
Практический материал

Разработка и Конфигурация · 13 мин

Инструкции препроцессора в 1С: что это и как их применять

Инструкции препроцессора 1С: #Если, #Тогда, #Иначе, #КонецЕсли. Как работают директивы Сервер, Клиент, ТонкийКлиент, примеры кода и типичные ошибки разработчиков.

При разработке на платформе «1С:Предприятие» один и тот же модуль нередко исполняется в разных средах: общий модуль может вызываться и на сервере, и на клиенте, а модуль формы компилируется отдельно для каждого контекста. Чтобы код корректно работал везде, платформа предоставляет инструкции препроцессора — специальные директивы, начинающиеся с символа «#».

Препроцессор обрабатывает текст модуля до его компиляции: в зависимости от того, где именно компилируется код (на сервере, в тонком клиенте, в веб-клиенте), часть строк просто исключается из итогового текста. То есть это не условный оператор «Если» встроенного языка — решение принимается не во время выполнения, а ещё на этапе подготовки кода.

Понимание инструкций препроцессора критично для разработчиков, которые пишут общие модули с несколькими флагами компиляции, работают с управляемыми формами или переносят код между клиент-серверными и файловыми информационными базами. Ниже разобраны все директивы, типовые сценарии и ошибки, которые чаще всего встречаются на практике.

Что такое препроцессор и как он работает в 1С

Препроцессор — это механизм платформы, который анализирует исходный текст модуля до его компиляции во внутренний байт-код. Встречая инструкцию вида #Если Сервер Тогда, препроцессор проверяет, соответствует ли текущая среда компиляции указанному условию. Если да — код внутри блока остаётся в модуле, если нет — строки отбрасываются и в скомпилированный модуль не попадают вовсе.

Ключевое следствие: код внутри «чужой» ветки не просто не выполняется — он физически отсутствует в скомпилированной версии. Поэтому обращение к несуществующей в данном контексте процедуре внутри правильно оформленной инструкции не вызовет ошибки, а та же строка без инструкции приведёт к ошибке компиляции.

Препроцессор в 1С работает на уровне текста, а не логики. Он не вычисляет выражения и не знает значений переменных — он лишь сопоставляет имя среды исполнения с условием инструкции. Это принципиально отличает его от условного оператора «Если … Тогда … КонецЕсли», который выполняется уже во время работы программы.

Синтаксис инструкций: #Если, #ИначеЕсли, #Иначе, #КонецЕсли

Полный набор инструкций препроцессора в 1С невелик. Основная конструкция выглядит так:

#Если Сервер Тогда

// код, который компилируется только на сервере

#ИначеЕсли ТонкийКлиент Тогда

// код для тонкого клиента

#Иначе

// код для всех остальных сред

#КонецЕсли

Условия инструкций — это предопределённые имена сред исполнения. В современных версиях платформы доступны следующие ключевые слова:

  • Сервер — код компилируется при исполнении на сервере 1С:Предприятия;
  • ТолстыйКлиентОбычноеПриложение — толстый клиент в режиме обычного приложения;
  • ТолстыйКлиентУправляемоеПриложение — толстый клиент в режиме управляемого приложения;
  • ТонкийКлиент — тонкий клиент;
  • ВебКлиент — веб-клиент;
  • МобильныйКлиент, МобильноеПриложениеКлиент, МобильноеПриложениеСервер — среды мобильной платформы;
  • ВнешнееСоединение — внешнее соединение (COM).

Инструкции можно вкладывать друг в друга, а условия внутри одной ветки комбинируются только через #ИначеЕсли — логические операторы «И/ИЛИ» в условиях препроцессора не поддерживаются. Если нужно охватить несколько сред (например, «тонкий клиент или веб-клиент»), придётся либо перечислить их через #ИначеЕсли с дублированием кода, либо использовать ветку #Иначе с исключением ненужных сред.

Отличие препроцессора от условного оператора и директив компиляции

Начинающие разработчики часто путают три похожих механизма: инструкции препроцессора, оператор «Если» встроенного языка и директивы компиляции «&НаСервере», «&НаКлиенте». Различия между ними принципиальны.

КритерийПрепроцессор (#Если)Оператор ЕслиДирективы &НаСервере/&НаКлиенте
Когда срабатываетДо компиляции модуляВо время выполненияПри компиляции модуля формы
Что делаетИсключает текст из модуляВыбирает ветку выполненияОпределяет контекст компиляции метода
Где применяетсяЛюбые модулиЛюбые модулиТолько модули форм и команд
Можно ли проверить переменнуюНетДаНет

Директивы компиляции (&НаСервере, &НаКлиенте, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста) действуют на уровне целого метода и работают только в модулях форм. Инструкции препроцессора, напротив, могут обрамлять любой фрагмент текста — хоть одну строку внутри процедуры, хоть объявление переменной, хоть целый метод — и применимы в любых модулях: общих, объектов, менеджеров, модуле приложения.

Практический вывод: если нужно разделить поведение внутри одной процедуры общего модуля — используйте препроцессор. Если разделяются целые методы формы — используйте директивы компиляции. Если выбор зависит от данных во время выполнения (например, от настройки пользователя) — только оператор «Если».

Типовые сценарии применения

Общий модуль с несколькими флагами компиляции

Самая частая ситуация — общий модуль, у которого одновременно установлены флаги «Сервер» и «Клиент (управляемое приложение)». Такой модуль компилируется в обеих средах, и код, допустимый только на сервере (например, прямые запросы к базе данных), нужно оборачивать в инструкции:

Функция ПолучитьКурсВалюты(Валюта) Экспорт

#Если Сервер Тогда

Запрос = Новый Запрос("ВЫБРАТЬ Курс ИЗ РегистрСведений.КурсыВалют...");

// выполнение запроса

Возврат Курс;

#Иначе

ВызватьИсключение "Функция доступна только на сервере";

#КонецЕсли

КонецФункции

Модуль формы: разное поведение в тонком и веб-клиенте

В модулях форм инструкции препроцессора применяют, когда возможности клиентов различаются. Например, работа с файловой системой в веб-клиенте требует расширения работы с файлами, а в тонком клиенте доступна напрямую:

&НаКлиенте

Процедура ВыбратьФайл(Команда)

#Если ВебКлиент Тогда

// логика через расширение работы с файлами

#ИначеЕсли ТонкийКлиент Тогда

Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);

// ...

#КонецЕсли

КонецПроцедуры

Отладочный код и файловый режим

Иногда инструкции используют для вставки служебного кода, который должен существовать только при отладке в толстом клиенте обычного приложения, где доступны некоторые инструменты, отсутствующие в управляемом режиме. Такой код оборачивают в #Если ТолстыйКлиентОбычноеПриложение Тогда, чтобы он не мешал компиляции в остальных средах.

Перед тем как оборачивать код в #Если Сервер, проверьте, не проще ли вынести серверную логику в отдельный общий модуль с единственным флагом «Сервер». Это делает код чище и снижает риск ошибок компиляции в клиентских средах.
ПЗ
Практическое замечание

Как проверить корректность кода в разных средах

Главная ловушка препроцессора — конфигуратор по умолчанию проверяет модуль в том контексте, который выбран в настройках, и ошибка внутри «невидимой» ветки может остаться незамеченной до запуска в нужном клиенте.

Как проверить модуль во всех средах
  1. 1
    Откройте модуль в конфигураторе и выполните «Текст → Проверка синтаксиса» (или Ctrl+F7 в редакторе модуля).
  2. 2
    В настройках проверки отметьте все режимы компиляции, в которых будет использоваться модуль: сервер, тонкий клиент, веб-клиент, толстый клиент.
  3. 3
    Проверьте, что флаги компиляции общего модуля соответствуют средам, указанным в инструкциях препроцессора.
  4. 4
    Запустите прикладное решение в каждом целевом клиенте и выполните сценарий, вызывающий изменённый код.
  5. 5
    При использовании расширенной проверки конфигурации включите её для всех режимов — она выявляет обращения к несуществующим в данном контексте объектам.

Признак правильно написанного кода: модуль успешно проходит синтаксическую проверку во всех выбранных режимах компиляции, а функциональность одинаково работает при запуске в тонком клиенте, веб-клиенте и на сервере. Если при переключении режима проверки появляются ошибки в строках, которые «раньше были зелёными», значит, часть кода попала не в ту ветку препроцессора.

Контрольные точки

Как проверить результат

Синтаксическая проверка модуля
Норма

Нет ошибок ни в одном режиме компиляции

Тревожный признак

Ошибки появляются только при выборе определённого режима — код вне нужной ветки

Запуск в целевом клиенте
Норма

Сценарий отрабатывает без исключений

Тревожный признак

Ошибка «Процедура или функция не обнаружена» в конкретном клиенте

Флаги общего модуля
Норма

Флаги соответствуют средам, где модуль реально вызывается

Тревожный признак

Модуль компилируется в среде, где его код не может работать

Типичные ошибки и ограничения

Первая и самая частая ошибка — попытка использовать в условии препроцессора логические выражения: #Если Сервер И Не ВебКлиент Тогда. Платформа такую конструкцию не поддерживает, и разработчик получает ошибку синтаксиса. Выход — перечисление сред через #ИначеЕсли или перестройка логики через ветку #Иначе.

Вторая ошибка — забытый #КонецЕсли или нарушенная вложенность инструкций. Поскольку препроцессор работает с текстом, незакрытая инструкция «съедает» весь код до конца модуля или до ближайшего закрывающего тега, что приводит к неожиданным ошибкам компиляции в строках, которые написаны правильно.

Третья группа проблем — обращение к контексту, недоступному в данной среде, внутри правильной ветки. Например, в ветке #Если ТонкийКлиент Тогда размещают код с прямым обращением к базе данных через запрос. Препроцессор такой текст пропустит, а ошибка всплывёт уже на этапе компиляции или выполнения в тонком клиенте.

Типичные ошибки
01
Использование логических операторов в условии #Если — препроцессор принимает только одно имя среды, выражение вызовет ошибку синтаксиса.
02
Пропущенный #КонецЕсли — весь последующий код модуля попадает внутрь ветки и исчезает из компиляции в других средах.
03
Проверка модуля только в одном режиме компиляции — ошибка в клиентской ветке обнаруживается у пользователя, а не у разработчика.
04
Размещение серверного кода (запросы, прикладные типы сервера) в клиентской ветке — препроцессор текст пропустит, но компиляция или выполнение завершатся ошибкой.
05
Злоупотребление препроцессором вместо выноса кода в отдельные общие модули — модуль становится трудно читать и сопровождать.

Альтернативы препроцессору: когда лучше обойтись без него

Инструкции препроцессора — не единственный способ разделить код по средам исполнения, и часто не самый удачный. Платформа предлагает более чистые архитектурные решения.

Способы разделения кода по контекстам

Отдельные общие модули

Модуль с флагом «Сервер» и отдельный модуль с флагом «Клиент». Самый читаемый вариант, но требует продуманной структуры модулей.

Директивы &НаСервере / &НаКлиенте

Подходят только для модулей форм и действуют на целый метод. Удобны, когда разделяется логика формы, а не общая функциональность.

Инструкции препроцессора

Единственный вариант, когда разделение нужно внутри одной процедуры общего модуля или в объявлениях переменных. Минус — код проверяется только в выбранном режиме компиляции.

Оператор Если с проверкой в runtime

Например, проверка значения функциональной опции. Работает во время выполнения, но не решает проблему недоступности типов в другой среде компиляции.

Рекомендация проста: препроцессор оправдан, когда различия между средами минимальны и локальны — несколько строк внутри процедуры, объявление переменной, обращение к специфичному для клиента объекту. Если серверная и клиентская логика существенно различаются, правильнее разнести их по отдельным общим модулям — такой код проще тестировать и сопровождать.

Итог

Что важно запомнить

Инструкции препроцессора (#Если, #ИначеЕсли, #Иначе, #КонецЕсли) определяют, какой текст попадёт в скомпилированный модуль для каждой среды исполнения. В условиях допустимо только одно имя среды, без логических операторов. Всегда проверяйте модуль во всех режимах компиляции и предпочитайте отдельные общие модули, когда различий между средами много.

Частые вопросы

Чем инструкция #Если отличается от оператора Если?

Инструкция препроцессора обрабатывается до компиляции и физически исключает текст из модуля для «чужой» среды. Оператор Если выполняется во время работы программы и может анализировать значения переменных. Препроцессор переменных не видит — он сравнивает только имя среды исполнения.

Можно ли написать условие вида «сервер или толстый клиент»?

Напрямую — нет, логические операторы в условиях препроцессора не поддерживаются. Используйте цепочку #ИначеЕсли с перечислением нужных сред или инвертируйте логику: перечислите в ветках те среды, где код не нужен, а рабочий код поместите в #Иначе.

Почему модуль проходит проверку, а у пользователя возникает ошибка?

Скорее всего, синтаксическая проверка выполнялась только в одном режиме компиляции (например, «Сервер»), а пользователь работает в тонком или веб-клиенте. Включите в настройках проверки все режимы, в которых используется модуль, и повторите проверку — ошибка проявится в конфигураторе.

Работают ли инструкции препроцессора в модулях форм?

Да, работают, и их можно комбинировать с директивами &НаСервере и &НаКлиенте. Например, внутри метода &НаКлиенте можно уточнить поведение для веб-клиента через #Если ВебКлиент. Однако для разделения целых методов формы директивы компиляции обычно удобнее.

Что произойдёт, если забыть #КонецЕсли?

Препроцессор будет считать весь последующий текст частью открытой ветки. В средах, где условие не выполняется, этот код исчезнет из компиляции; в среде, где условие истинно, компилятор, скорее всего, сообщит об ошибке синтаксиса из-за незакрытой инструкции. Всегда проверяйте парность #Если и #КонецЕсли, особенно при вложенных конструкциях.

Нужен ли препроцессор в файловом режиме работы?

Да. Файловый режим не отменяет разделения контекстов: тонкий клиент, веб-клиент и серверная часть по-прежнему компилируют модули отдельно, и ограничения на доступные типы и объекты сохраняются. Инструкции препроцессора работают одинаково в файловом и клиент-серверном вариантах.