Как правильно написать условие, что реквизит документа не равен значению перечисления в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке во встроенном языке 1С:Предприятие часто возникает задача проверить, что реквизит некоторого объекта (например, документа или справочника) не равен определенному значению перечисления. Начинающие разработчики часто сталкиваются с дилеммой: какой синтаксис использовать для этой проверки? Существует несколько вариантов написания такого условия с использованием оператора равенства =, отрицания НЕ и оператора «не равно» <>. Какой из них является наиболее быстрым, правильным с точки зрения стандартов и безопасным для системы? Давайте разберем этот вопрос подробно и по шагам.

Анализ четырех базовых вариантов написания условия

Рассмотрим четыре типичных варианта написания условия, которые чаще всего встречаются в кодовой базе и вызывают споры среди разработчиков:

  1. Если ТекущийЗаказ.ВидОперации = НЕ Перечисления.ВидыОпераций.Первичный Тогда
  2. Если НЕ ТекущийЗаказ.ВидОперации = Перечисления.ВидыОпераций.Первичный Тогда
  3. Если НЕ (ТекущийЗаказ.ВидОперации = Перечисления.ВидыОпераций.Первичный) Тогда
  4. Если ТекущийЗаказ.ВидОперации <> Перечисления.ВидыОпераций.Первичный Тогда

Проанализируем поведение платформы 1С при выполнении каждого из этих вариантов и выясним причины их работоспособности или падения с ошибкой.

Вариант №1: Ошибочный синтаксис. Данный вариант гарантированно приведет к аварийному завершению работы программы с ошибкой преобразования типов. Дело в том, что унарный оператор логического отрицания НЕ применяется непосредственно к значению перечисления Перечисления.ВидыОпераций.Первичный. Платформа попытается привести ссылку перечисления к логическому типу Булево, чтобы выполнить операцию отрицания, что завершится ошибкой выполнения (Runtime Error).

Вариант №2 и Вариант №3: Рабочие, но избыточные конструкции. Оба этих варианта отработают абсолютно корректно и одинаково. В среде разработчиков часто возникает путаница с приоритетом выполнения оператора НЕ и оператора равенства =. Обратимся к таблице приоритетов операторов встроенного языка 1С. Операторы в ней расположены в порядке увеличения приоритета (от низшего к высшему):

Поскольку оператор сравнения = находится ниже в списке, он имеет более высокий приоритет вычисления, чем логическое отрицание НЕ. Это означает, что в выражении без скобок НЕ ТекущийЗаказ.ВидОперации = Перечисления.ВидыОпераций.Первичный платформа сначала выполнит операцию сравнения на равенство, получит результат типа Булево (Истина или Ложь), и только после этого применит к полученному булеву значению оператор отрицания НЕ. Таким образом, скобки в Варианте №3 являются синтаксически избыточными, хотя и делают код более понятным для разработчиков, пришедших из других языков программирования.

Вариант №4: Наиболее оптимальный и лаконичный вариант. Использование прямого оператора «не равно» <> является классическим решением. Проанализируем ситуацию подробнее: этот вариант наиболее прост для чтения человеком, не перегружает когнитивную систему двойными отрицаниями и транслируется виртуальной машиной 1С в одно действие сравнения, в отличие от вариантов с оператором НЕ, которые выполняют два последовательных шага вычислений.

Рассмотрим правильный пример написания условия:


Если ТекущийЗаказ.ВидОперации <> Перечисления.ВидыОпераций.Первичный Тогда
    // Выполняем действия, если вид операции не равен первичному
    ОбработатьЗаказ(ТекущийЗаказ);
КонецЕсли;

Прямое обращение против функции ПредопределенноеЗначение

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

Рассмотрим вариант с использованием системной функции:


Если ТекущийЗаказ.ВидОперации <> ПредопределенноеЗначение("Перечисление.ВидыОпераций.Первичный") Тогда
    // Код обработки
КонецЕсли;

Выясним причину, почему и когда следует (или не следует) использовать данный подход:

1. Контекст исполнения (Клиент или Сервер). Это главное архитектурное различие. На стороне сервера разработчику всегда доступны менеджеры объектов встроенного языка. Прямое обращение к объектам метаданных через точку Перечисления.ВидыОпераций.Первичный на сервере работает максимально быстро. Платформа мгновенно возвращает типизированную ссылку из кэша сервера.

Если же код выполняется на стороне тонкого или веб-клиента, менеджеры метаданных (такие как Перечисления) недоступны. Попытка написать обращение через точку в клиентской процедуре вызовет синтаксическую ошибку при компиляции модуля. Именно для решения этой проблемы была создана функция ПредопределенноеЗначение(). Она позволяет получить ссылку на предопределенный элемент или значение перечисления непосредственно на клиенте.

2. Производительность парсинга строки. При использовании функции ПредопределенноеЗначение("ПутьКДанным") платформа вынуждена тратить дополнительные ресурсы процессора на синтаксический анализ (парсинг) переданной текстовой строки, чтобы определить, к какому типу и объекту метаданных идет обращение. На сервере выполнять такую операцию крайне не рекомендуется. Прямое обращение к менеджеру объектов работает значительно быстрее и не создает лишней нагрузки.

3. Кэширование данных. Системная функция действительно кэширует результат своего выполнения при первом вызове на клиенте до изменения конфигурации или версии платформы. Однако первый вызов все равно инициирует неявный серверный вызов для получения значения. Чтобы избежать подобных скрытых вызовов в тяжелых формах, хорошим тоном считается кэширование необходимых значений на сервере при создании формы и передача их на клиент через переменные модуля или параметры формы.

Безопасность кода при работе с составными типами и значениями NULL

Если реквизит документа ВидОперации имеет составной тип данных (например, может принимать значения нескольких различных перечислений или справочников) или если данные выбираются из базы данных посредством запроса с использованием левого соединения (где результатом может быть значение NULL), обычное сравнение «в лоб» через <> может повести себя непредсказуемо или вызвать ошибку несовместимости типов.

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


Если ЗначениеЗаполнено(ТекущийЗаказ.ВидОперации) Тогда
    
    // Проверяем, совпадает ли тип значения реквизита с типом нашего перечисления
    Если ТипЗнч(ТекущийЗаказ.ВидОперации) = Тип("ПеречислениеСсылка.ВидыОпераций") Тогда
        
        // Теперь сравнение абсолютно безопасно
        Если ТекущийЗаказ.ВидОперации <> Перечисления.ВидыОпераций.Первичный Тогда
            ВыполнитьДействие();
        КонецЕсли;
        
    КонецЕсли;
    
КонецЕсли;

Использование Библиотеки стандартных подсистем (БСП)

В современных конфигурациях, построенных на базе БСП (ERP, Управление торговлей, Комплексная автоматизация, ЗУП), разработчикам доступен еще один продвинутый инструмент — функции общего назначения. Вместо платформенной функции ПредопределенноеЗначение() рекомендуется задействовать функции БСП:

Основное преимущество функций БСП перед платформенным аналогом заключается в обработке исключительных ситуаций. Если предопределенный элемент (или значение перечисления) был случайно удален или переименован в конфигураторе, стандартная функция ПредопределенноеЗначение() вызовет жесткое падение системы с критической ошибкой. Функция БСП в этом случае вернет значение Неопределено, что позволит приложению продолжить работу без аварийного завершения.

Пример интеграции безопасного метода БСП:


НужноеЗначение = ОбщегоНазначения.ПредопределенныйЭлемент("Перечисление.ВидыОпераций.Первичный");

Если ЗначениеЗаполнено(НужноеЗначение) Тогда
    Если ТекущийЗаказ.ВидОперации <> НужноеЗначение Тогда
        // Безопасно выполняем обработку
        ПровестиДокумент(ТекущийЗаказ);
    КонецЕсли;
КонецЕсли;

Резюме и рекомендации

Подводя итоги нашего подробного разбора, выделим ключевые правила для написания качественного, быстрого и читаемого кода в 1С:

← На главную