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