Разработка и Конфигурация · 13 мин
Инструкции препроцессора в 1С: что это и как их применять
Инструкции препроцессора 1С: #Если, #Тогда, #Иначе, #КонецЕсли. Как работают директивы Сервер, Клиент, ТонкийКлиент, примеры кода и типичные ошибки разработчиков.
При разработке на платформе «1С:Предприятие» один и тот же модуль нередко исполняется в разных средах: общий модуль может вызываться и на сервере, и на клиенте, а модуль формы компилируется отдельно для каждого контекста. Чтобы код корректно работал везде, платформа предоставляет инструкции препроцессора — специальные директивы, начинающиеся с символа «#».
Препроцессор обрабатывает текст модуля до его компиляции: в зависимости от того, где именно компилируется код (на сервере, в тонком клиенте, в веб-клиенте), часть строк просто исключается из итогового текста. То есть это не условный оператор «Если» встроенного языка — решение принимается не во время выполнения, а ещё на этапе подготовки кода.
Понимание инструкций препроцессора критично для разработчиков, которые пишут общие модули с несколькими флагами компиляции, работают с управляемыми формами или переносят код между клиент-серверными и файловыми информационными базами. Ниже разобраны все директивы, типовые сценарии и ошибки, которые чаще всего встречаются на практике.
Что такое препроцессор и как он работает в 1С
Препроцессор — это механизм платформы, который анализирует исходный текст модуля до его компиляции во внутренний байт-код. Встречая инструкцию вида #Если Сервер Тогда, препроцессор проверяет, соответствует ли текущая среда компиляции указанному условию. Если да — код внутри блока остаётся в модуле, если нет — строки отбрасываются и в скомпилированный модуль не попадают вовсе.
Ключевое следствие: код внутри «чужой» ветки не просто не выполняется — он физически отсутствует в скомпилированной версии. Поэтому обращение к несуществующей в данном контексте процедуре внутри правильно оформленной инструкции не вызовет ошибки, а та же строка без инструкции приведёт к ошибке компиляции.
Препроцессор в 1С работает на уровне текста, а не логики. Он не вычисляет выражения и не знает значений переменных — он лишь сопоставляет имя среды исполнения с условием инструкции. Это принципиально отличает его от условного оператора «Если … Тогда … КонецЕсли», который выполняется уже во время работы программы.
Синтаксис инструкций: #Если, #ИначеЕсли, #Иначе, #КонецЕсли
Полный набор инструкций препроцессора в 1С невелик. Основная конструкция выглядит так:
#Если Сервер Тогда
// код, который компилируется только на сервере
#ИначеЕсли ТонкийКлиент Тогда
// код для тонкого клиента
#Иначе
// код для всех остальных сред
#КонецЕсли
Условия инструкций — это предопределённые имена сред исполнения. В современных версиях платформы доступны следующие ключевые слова:
Сервер— код компилируется при исполнении на сервере 1С:Предприятия;ТолстыйКлиентОбычноеПриложение— толстый клиент в режиме обычного приложения;ТолстыйКлиентУправляемоеПриложение— толстый клиент в режиме управляемого приложения;ТонкийКлиент— тонкий клиент;ВебКлиент— веб-клиент;МобильныйКлиент,МобильноеПриложениеКлиент,МобильноеПриложениеСервер— среды мобильной платформы;ВнешнееСоединение— внешнее соединение (COM).
Инструкции можно вкладывать друг в друга, а условия внутри одной ветки комбинируются только через #ИначеЕсли — логические операторы «И/ИЛИ» в условиях препроцессора не поддерживаются. Если нужно охватить несколько сред (например, «тонкий клиент или веб-клиент»), придётся либо перечислить их через #ИначеЕсли с дублированием кода, либо использовать ветку #Иначе с исключением ненужных сред.
Отличие препроцессора от условного оператора и директив компиляции
Начинающие разработчики часто путают три похожих механизма: инструкции препроцессора, оператор «Если» встроенного языка и директивы компиляции «&НаСервере», «&НаКлиенте». Различия между ними принципиальны.
| Критерий | Препроцессор (#Если) | Оператор Если | Директивы &НаСервере/&НаКлиенте |
|---|---|---|---|
| Когда срабатывает | До компиляции модуля | Во время выполнения | При компиляции модуля формы |
| Что делает | Исключает текст из модуля | Выбирает ветку выполнения | Определяет контекст компиляции метода |
| Где применяется | Любые модули | Любые модули | Только модули форм и команд |
| Можно ли проверить переменную | Нет | Да | Нет |
Директивы компиляции (&НаСервере, &НаКлиенте, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста) действуют на уровне целого метода и работают только в модулях форм. Инструкции препроцессора, напротив, могут обрамлять любой фрагмент текста — хоть одну строку внутри процедуры, хоть объявление переменной, хоть целый метод — и применимы в любых модулях: общих, объектов, менеджеров, модуле приложения.
Практический вывод: если нужно разделить поведение внутри одной процедуры общего модуля — используйте препроцессор. Если разделяются целые методы формы — используйте директивы компиляции. Если выбор зависит от данных во время выполнения (например, от настройки пользователя) — только оператор «Если».
Типовые сценарии применения
Общий модуль с несколькими флагами компиляции
Самая частая ситуация — общий модуль, у которого одновременно установлены флаги «Сервер» и «Клиент (управляемое приложение)». Такой модуль компилируется в обеих средах, и код, допустимый только на сервере (например, прямые запросы к базе данных), нужно оборачивать в инструкции:
Функция ПолучитьКурсВалюты(Валюта) Экспорт
#Если Сервер Тогда
Запрос = Новый Запрос("ВЫБРАТЬ Курс ИЗ РегистрСведений.КурсыВалют...");
// выполнение запроса
Возврат Курс;
#Иначе
ВызватьИсключение "Функция доступна только на сервере";
#КонецЕсли
КонецФункции
Модуль формы: разное поведение в тонком и веб-клиенте
В модулях форм инструкции препроцессора применяют, когда возможности клиентов различаются. Например, работа с файловой системой в веб-клиенте требует расширения работы с файлами, а в тонком клиенте доступна напрямую:
&НаКлиенте
Процедура ВыбратьФайл(Команда)
#Если ВебКлиент Тогда
// логика через расширение работы с файлами
#ИначеЕсли ТонкийКлиент Тогда
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
// ...
#КонецЕсли
КонецПроцедуры
Отладочный код и файловый режим
Иногда инструкции используют для вставки служебного кода, который должен существовать только при отладке в толстом клиенте обычного приложения, где доступны некоторые инструменты, отсутствующие в управляемом режиме. Такой код оборачивают в #Если ТолстыйКлиентОбычноеПриложение Тогда, чтобы он не мешал компиляции в остальных средах.
Перед тем как оборачивать код в #Если Сервер, проверьте, не проще ли вынести серверную логику в отдельный общий модуль с единственным флагом «Сервер». Это делает код чище и снижает риск ошибок компиляции в клиентских средах.
Как проверить корректность кода в разных средах
Главная ловушка препроцессора — конфигуратор по умолчанию проверяет модуль в том контексте, который выбран в настройках, и ошибка внутри «невидимой» ветки может остаться незамеченной до запуска в нужном клиенте.
- 1Откройте модуль в конфигураторе и выполните «Текст → Проверка синтаксиса» (или Ctrl+F7 в редакторе модуля).
- 2В настройках проверки отметьте все режимы компиляции, в которых будет использоваться модуль: сервер, тонкий клиент, веб-клиент, толстый клиент.
- 3Проверьте, что флаги компиляции общего модуля соответствуют средам, указанным в инструкциях препроцессора.
- 4Запустите прикладное решение в каждом целевом клиенте и выполните сценарий, вызывающий изменённый код.
- 5При использовании расширенной проверки конфигурации включите её для всех режимов — она выявляет обращения к несуществующим в данном контексте объектам.
Признак правильно написанного кода: модуль успешно проходит синтаксическую проверку во всех выбранных режимах компиляции, а функциональность одинаково работает при запуске в тонком клиенте, веб-клиенте и на сервере. Если при переключении режима проверки появляются ошибки в строках, которые «раньше были зелёными», значит, часть кода попала не в ту ветку препроцессора.
Как проверить результат
Нет ошибок ни в одном режиме компиляции
Ошибки появляются только при выборе определённого режима — код вне нужной ветки
Сценарий отрабатывает без исключений
Ошибка «Процедура или функция не обнаружена» в конкретном клиенте
Флаги соответствуют средам, где модуль реально вызывается
Модуль компилируется в среде, где его код не может работать
Типичные ошибки и ограничения
Первая и самая частая ошибка — попытка использовать в условии препроцессора логические выражения: #Если Сервер И Не ВебКлиент Тогда. Платформа такую конструкцию не поддерживает, и разработчик получает ошибку синтаксиса. Выход — перечисление сред через #ИначеЕсли или перестройка логики через ветку #Иначе.
Вторая ошибка — забытый #КонецЕсли или нарушенная вложенность инструкций. Поскольку препроцессор работает с текстом, незакрытая инструкция «съедает» весь код до конца модуля или до ближайшего закрывающего тега, что приводит к неожиданным ошибкам компиляции в строках, которые написаны правильно.
Третья группа проблем — обращение к контексту, недоступному в данной среде, внутри правильной ветки. Например, в ветке #Если ТонкийКлиент Тогда размещают код с прямым обращением к базе данных через запрос. Препроцессор такой текст пропустит, а ошибка всплывёт уже на этапе компиляции или выполнения в тонком клиенте.
Альтернативы препроцессору: когда лучше обойтись без него
Инструкции препроцессора — не единственный способ разделить код по средам исполнения, и часто не самый удачный. Платформа предлагает более чистые архитектурные решения.
Способы разделения кода по контекстам
Модуль с флагом «Сервер» и отдельный модуль с флагом «Клиент». Самый читаемый вариант, но требует продуманной структуры модулей.
Подходят только для модулей форм и действуют на целый метод. Удобны, когда разделяется логика формы, а не общая функциональность.
Единственный вариант, когда разделение нужно внутри одной процедуры общего модуля или в объявлениях переменных. Минус — код проверяется только в выбранном режиме компиляции.
Например, проверка значения функциональной опции. Работает во время выполнения, но не решает проблему недоступности типов в другой среде компиляции.
Рекомендация проста: препроцессор оправдан, когда различия между средами минимальны и локальны — несколько строк внутри процедуры, объявление переменной, обращение к специфичному для клиента объекту. Если серверная и клиентская логика существенно различаются, правильнее разнести их по отдельным общим модулям — такой код проще тестировать и сопровождать.
Что важно запомнить
Инструкции препроцессора (#Если, #ИначеЕсли, #Иначе, #КонецЕсли) определяют, какой текст попадёт в скомпилированный модуль для каждой среды исполнения. В условиях допустимо только одно имя среды, без логических операторов. Всегда проверяйте модуль во всех режимах компиляции и предпочитайте отдельные общие модули, когда различий между средами много.
Частые вопросы
Чем инструкция #Если отличается от оператора Если?
Инструкция препроцессора обрабатывается до компиляции и физически исключает текст из модуля для «чужой» среды. Оператор Если выполняется во время работы программы и может анализировать значения переменных. Препроцессор переменных не видит — он сравнивает только имя среды исполнения.
Можно ли написать условие вида «сервер или толстый клиент»?
Напрямую — нет, логические операторы в условиях препроцессора не поддерживаются. Используйте цепочку #ИначеЕсли с перечислением нужных сред или инвертируйте логику: перечислите в ветках те среды, где код не нужен, а рабочий код поместите в #Иначе.
Почему модуль проходит проверку, а у пользователя возникает ошибка?
Скорее всего, синтаксическая проверка выполнялась только в одном режиме компиляции (например, «Сервер»), а пользователь работает в тонком или веб-клиенте. Включите в настройках проверки все режимы, в которых используется модуль, и повторите проверку — ошибка проявится в конфигураторе.
Работают ли инструкции препроцессора в модулях форм?
Да, работают, и их можно комбинировать с директивами &НаСервере и &НаКлиенте. Например, внутри метода &НаКлиенте можно уточнить поведение для веб-клиента через #Если ВебКлиент. Однако для разделения целых методов формы директивы компиляции обычно удобнее.
Что произойдёт, если забыть #КонецЕсли?
Препроцессор будет считать весь последующий текст частью открытой ветки. В средах, где условие не выполняется, этот код исчезнет из компиляции; в среде, где условие истинно, компилятор, скорее всего, сообщит об ошибке синтаксиса из-за незакрытой инструкции. Всегда проверяйте парность #Если и #КонецЕсли, особенно при вложенных конструкциях.
Нужен ли препроцессор в файловом режиме работы?
Да. Файловый режим не отменяет разделения контекстов: тонкий клиент, веб-клиент и серверная часть по-прежнему компилируют модули отдельно, и ограничения на доступные типы и объекты сохраняются. Инструкции препроцессора работают одинаково в файловом и клиент-серверном вариантах.