Как вычисляются составные логические условия в 1С:Предприятие 7.7 и 8.х и как избежать ошибок

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке алгоритмов и бизнес-логики на платформе 1С разработчики часто используют составные логические условия с операторами И (AND) и ИЛИ (OR). Однако поведение системы при выполнении таких условий кардинально отличается в зависимости от версии платформы — 1С:Предприятие 7.7 или 1С:Предприятие 8.х. Разберем подробно, почему возникает эта разница, к каким критическим ошибкам она может привести и как правильно составлять безопасный код.

Главное различие: полное и сокращенное вычисление условий

Выясним основной технический нюанс работы платформы с логическими выражениями.

1С:Предприятие 7.7 — Полная схема вычисления (Full Evaluation)
В платформе 7.7 всегда вычисляются все подвыражения, входящие в составное условие, независимо от результата первой части выражения:

  1. Если в выражении Условие1 И Условие2 первая часть Условие1 возвращает Ложь, платформа 1С 7.7 всё равно продолжит выполнение и вычислит Условие2.
  2. Если в выражении Условие1 ИЛИ Условие2 первая часть Условие1 возвращает Истина, правая часть Условие2 также будет вычислена.

1С:Предприятие 8.х — Сокращенная схема вычисления (Short-circuit Evaluation)
В платформе 8.х используются так называемые «ленивые вычисления». Платформа прекращает вычисление логического выражения сразу же, как только итоговый результат становится гарантирован:

  1. Для оператора И: если первое условие равно Ложь, второе условие даже не начинает вычисляться.
  2. Для оператора ИЛИ: если первое условие равно Истина, проверка последующих условий пропускается.

Экспериментальная проверка поведения в 1С 7.7

Проанализируем простую ситуацию с помощью наглядного теста. Напишем следующий код в платформе 1С 7.7:


Если (1 > 2) И (0 / 0 = 5) Тогда
    Предупреждение("Условие выполнено");
КонецЕсли;

Очевидно, что левая часть (1 > 2) ложна. Если бы платформа использовала сокращенную схему, правая часть (0 / 0 = 5) не должна была исполняться. Однако при запуске этого кода в 1С 7.7 система выдаст критическую ошибку «Деление на ноль». Это наглядно подтверждает, что в 1С 7.7 всегда проверяются все операнды логической цепочки.

Чем опасна полная схема вычисления в 1С 7.7

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


Если (Конт.Вид() = "РеализацияРозница") И (Найти(Врег(Контрагент.Наименование), "VISA") > 0) Тогда
    // Выполнение операций
КонецЕсли;

Если текущий документ не является документами вида «РеализацияРозница», или у него не выбран контрагент (значение Контрагент не заполнено), обращение к Контрагент.Наименование вызовет ошибку времени выполнения (Runtime Error). Из-за того, что в 1С 7.7 вычисляются обе части выражения, программа завершит работу с ошибкой обращения к реквизиту незаполненного объекта, несмотря на то, что первая проверка вернула Ложь.

Способы решения проблемы и написания безопасного кода в 1С 7.7

Разберем основные методы обхода этого ограничения в 1С:Предприятие 7.7.

Вариант 1. Использование каскада вложенных условий «Если»

Самый простой, понятный и надежный способ — разбить единое составное условие на несколько вложенных операторов Если ... Тогда. В этом случае внутренние блоки кода гарантированно не выполнятся, если внешняя проверка возвращает Ложь.


Если Конт.Вид() = "РеализацияРозница" Тогда
    Если Контрагент.Выбран() = 1 Тогда
        Если Найти(Врег(Контрагент.Наименование), "VISA") > 0 Тогда
            // Безопасное выполнение логики
        КонецЕсли;
    КонецЕсли;
КонецЕсли;

Вариант 2. Предварительная подготовка безопасных значений

Посмотрим на пример, когда перед выполнением сложного составного условия логические значения или наименования реквизитов предварительно рассчитываются и записываются в промежуточные переменные.


// Проверяем наличие реквизита или заполненность контрагента до основного условия
Если глЕстьРеквизитШапки("Контрагент", Конт.Вид()) = 1 Тогда
    ЛокальныйКонтрагент = Конт.Контрагент;
Иначе
    ЛокальныйКонтрагент = ПолучитьПустоеЗначение("Справочник.Контрагенты");
КонецЕсли;

Если ЛокальныйКонтрагент.Выбран() = 1 Тогда
    НаимКонтрагента = Врег(ЛокальныйКонтрагент.Наименование);
Иначе
    НаимКонтрагента = "";
КонецЕсли;

// Теперь сложное составное условие абсолютно безопасно
Если ((Конт.Вид() = "РеализацияРозница") И (Найти(НаимКонтрагента, "VISA") > 0) И (Конт.ДокОснование.Вид() = "ЗаявкаПокупателя")) 
   ИЛИ (Конт.Вид() = "ОтчетККМ") 
   ИЛИ ((Конт.Вид() = "ЧекККМ") И (Конт.ДокОснование.Вид() = "ЗаявкаПокупателя")) Тогда
    
    // Выполнение бизнес-логики
КонецЕсли;

Оптимизация кода в 1С:Предприятие 8.х

В платформе 1С 8.х благодаря «ленивым вычислениям» разработчики могут писать безопасный код в одну строку:


Если ЗначениеЗаполнено(Ссылка) И Ссылка.Реквизит = "Значение" Тогда
    // Если Ссылка не заполнена, обращение к Ссылка.Реквизит не произойдет
КонецЕсли;

Для повышения производительности в 1С 8.х рекомендуется соблюдать следующие правила оформления условий:

  1. При использовании оператора И в самое начало (слева) нужно ставить самые быстрые проверки или условия, которые с наибольшей вероятностью вернуть Ложь.
  2. При использовании оператора ИЛИ в самое начало нужно ставить условия, которые наиболее часто возвращают Истина.
  3. Вызовы ресурсоемких функций и запросов к базе данных следует располагать в самом конце цепочки условий, чтобы они срабатывали только при реальной необходимости.
← На главную