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

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

Директивы препроцессора в 1С 8.3: что это и как с ними работать

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

Директивы препроцессора в 1С 8.3 — это специальные инструкции, которые обрабатываются ещё до компиляции модуля и определяют, какие фрагменты кода попадут в итоговый исполняемый текст для конкретной среды исполнения. Они нужны, потому что один и тот же общий модуль может выполняться на сервере, на тонком клиенте, в толстом клиенте или в веб-клиенте, а набор доступных объектов и функций в каждой среде разный.

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

Важно понимать: препроцессор работает до выполнения кода. Это не условный оператор Если...Тогда, который проверяется в рантайме. Директива физически исключает текст из модуля для конкретного контекста, поэтому в коде, попавшем на тонкий клиент, не будет даже синтаксической проверки серверных вызовов, заключённых в ветку «Сервер».

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

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

Следствие из этого механизма: код, исключённый директивами, не проверяется на синтаксические ошибки в данной среде и не занимает память. Это принципиальное отличие от обычного условия Если ТонкийКлиент() Тогда ... — такого вызова в платформе в рантайме нет, а попытка обернуть серверный вызов в обычное условие приведёт к ошибке компиляции на клиенте.

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

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

Набор директив в 1С невелик и напоминает условный оператор, только с символом решётки в начале:

  • #Если <логическое выражение> Тогда — начало условного блока;
  • #ИначеЕсли <логическое выражение> Тогда — альтернативная ветка;
  • #Иначе — ветка, если ни одно условие не выполнилось;
  • #КонецЕсли — обязательное завершение конструкции.

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

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

// Этот код попадёт только в серверный контекст

Запрос = Новый Запрос("ВЫБРАТЬ ...");

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

// Только тонкий клиент

ПоказатьПредупреждение(, "Операция выполняется на сервере");

#Иначе

// Все остальные клиентские среды

#КонецЕсли

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

Символы препроцессора и среды исполнения

Значение символов зависит от того, где исполняется модуль. Основные символы, доступные в платформе 8.3:

СимволГде истиненТипичное применение
СерверСервер 1С:ПредприятияЗапросы к БД, работа с СУБД, файловые операции на сервере
ТолстыйКлиентОбычноеПриложениеТолстый клиент, обычные формыУстаревшие интерфейсные механизмы, OLE/COM
ТолстыйКлиентУправляемоеПриложениеТолстый клиент, управляемые формыКод, недоступный в тонком/веб-клиенте
ТонкийКлиентТонкий клиентОсновная клиентская ветка управляемых приложений
ВебКлиентВеб-клиент (браузер)Обход ограничений браузерной среды
МобильныйКлиентМобильный клиентОсобенности мобильной платформы
КлиентЛюбой клиентский контекстОбщая клиентская логика без уточнения вида
ВнешнееСоединениеCOM-соединениеИнтеграционные сценарии через внешнее соединение

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

Также существуют символы локализации — например, НаРусскомЯзыке — для кода, зависящего от встроенного языка конфигурации. Они применяются редко, в основном в многоязычных решениях.

Где директивы применяются на практике

Общие модули с несколькими контекстами

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

Модули форм

В модуле управляемой формы код исполняется и на клиенте, и на сервере (через директивы компиляции &НаКлиенте, &НаСервере). Директивы препроцессора здесь нужны, когда даже внутри клиентского метода поведение различается: например, в веб-клиенте недоступна работа с локальной файловой системой, и ветку с НачатьПомещениеФайла приходится оборачивать в #Если НЕ ВебКлиент Тогда.

Обход ограничений веб-клиента

Веб-клиент — самая ограниченная среда: нет прямого доступа к файловой системе, часть модальных методов работает иначе, недоступны некоторые объекты. Типовые конфигурации пестрят конструкциями вида #Если ВебКлиент Тогда именно для подстановки альтернативных реализаций.

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

Директивы препроцессора и директивы компиляции: в чём разница

Их часто путают, потому что обе связаны с контекстом исполнения. Различие принципиально:

  • Директивы препроцессора (#Если ... #КонецЕсли) работают с текстом модуля и физически исключают код до компиляции. Применимы в любом модуле.
  • Директивы компиляции (&НаКлиенте, &НаСервере, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста) указывают, в каком контексте компилируется вся процедура или функция модуля формы. Они не исключают код, а определяют его «место жительства».

Директивы компиляции существуют только в модулях форм (и команд), тогда как препроцессор доступен везде. Внутри процедуры с &НаКлиенте можно дополнительно использовать #Если ВебКлиент Тогда — механизмы дополняют друг друга, а не заменяют.

Что выбрать

Директивы препроцессора (#Если)

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

Директивы компиляции (&НаКлиенте/&НаСервере)

Подходят для разделения методов формы по контекстам исполнения и управления передачей данных между клиентом и сервером. Только в модулях форм.

Разделение на разные общие модули

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

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

Первая частая ошибка — попытка использовать в директиве рантайм-значение: #Если РольДоступна("Админ") Тогда. Препроцессор не выполняет код, выражение должно состоять только из символов и логических операций. Проверки прав, настроек и данных делаются обычным Если в рантайме.

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

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

Отдельное ограничение: директивы препроцессора не работают в выражениях, вычисляемых вне модулей (например, в строках, передаваемых в Вычислить() или Выполнить()), — там препроцессорный этап обрабатывается иначе, и полагаться на символы среды в таких строках нельзя без дополнительной проверки.

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

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

Главный инструмент проверки — «Проверка конфигурации» в конфигураторе с отмеченными режимами: «Тонкий клиент», «Веб-клиент», «Сервер», «Толстый клиент». Платформа компилирует модули для каждого выбранного контекста и покажет ошибки во всех ветках препроцессора.

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

Быстрый способ убедиться, что ветка исполняется, — временно добавить в неё вызов Сообщить() или запись в журнал регистрации и прогнать сценарий в каждой целевой среде. После проверки отладочный вывод удаляют.

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

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

Проверка конфигурации
Норма

Нет ошибок компиляции во всех включённых режимах (сервер, тонкий, веб-клиент)

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

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

Исполнение в целевой среде
Норма

Нужная ветка реально выполняется, поведение соответствует ожиданию

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

Код ветки молча пропускается — неверно выбран символ препроцессора

Читаемость модуля
Норма

Директив немного, каждая оборачивает целостный логический блок

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

В процедуре несколько вложенных #Если — код стоит разнести по модулям

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

Часто задаваемые вопросы

Чем директива препроцессора отличается от обычного оператора Если?

Оператор Если выполняется в рантайме и лишь выбирает ветку исполнения — весь код при этом компилируется и должен быть синтаксически корректен в данной среде. Директива #Если работает до компиляции и физически исключает текст из модуля, поэтому внутри её веток допустим код, несовместимый с текущей средой.

Можно ли использовать директивы препроцессора в модуле формы?

Да, директивы препроцессора работают в модулях форм наряду с директивами компиляции &НаКлиенте и &НаСервере. Типичный случай — различение тонкого и веб-клиента внутри клиентской процедуры, например при работе с файлами.

Почему код внутри #Если не подсвечивается ошибкой, хотя там опечатка?

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

Какие символы препроцессора использовать для «любого клиента»?

Используйте символ Клиент — он истинен в тонком, толстом, веб- и мобильном клиенте. Это короче и надёжнее, чем перечисление видов клиентов через ИЛИ, и не требует правки при появлении новых клиентских сред.

Можно ли проверять в директиве права пользователя или значения настроек?

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

Когда вместо директив лучше разделить код на разные модули?

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

Итог

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

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