Почему выражение Истина ИЛИ Неопределено вызывает ошибку преобразования типов под разными ролями в 1С?

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

В практике разработки на платформе 1С:Предприятие 8 часто возникает ситуация, когда один и тот же программный код ведет себя по-разному в зависимости от прав доступа пользователя. Одной из наиболее неочевидных проблем является ошибка «Преобразование значения к типу Булево не может быть выполнено», возникающая внутри логических конструкций Если ... Тогда или при присваивании логического значения переменной. Рассмотрим подробнее, почему выражение, которое успешно работает у администратора, может приводить к аварийному завершению сеанса у обычного пользователя.

Механизм ленивых вычислений в 1С

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

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

Рассмотрим это на примере кода из обсуждения:

Флаг = РольДоступна("ПолныеПрава") Или П1 Или Ф1;

Проанализируем ситуацию для двух разных пользователей:

  1. Пользователь с полными правами: Функция РольДоступна("ПолныеПрава") возвращает значение Истина. Платформа видит, что первое условие в цепочке ИЛИ выполнено, и сразу возвращает результат Истина. Переменные П1 и Ф1 даже не запрашиваются из памяти и не проверяются. Если в них в этот момент находится Неопределено, ошибка не возникнет.
  2. Пользователь с ограниченными правами: Функция РольДоступна() возвращает Ложь. Чтобы определить итоговое значение переменной Флаг, платформа вынуждена перейти ко второму операнду — П1. Если в П1 содержится значение типа Неопределено (например, реквизит не заполнен или функция поиска не вернула результат), система попытается применить к нему логическую операцию.

Причина возникновения ошибки преобразования типов

Выясним причину, по которой 1С выдает ошибку. В отличие от некоторых других языков программирования (например, JavaScript), где значения undefined или 0 могут быть неявно приведены к false, встроенный язык 1С придерживается строгой типизации для логических операций. Операндами для И, ИЛИ, НЕ могут выступать только значения типа Булево.

Когда система доходит до вычисления переменной П1, имеющей тип Неопределено, в контексте логического выражения, она пытается привести это значение к Булево. Поскольку автоматическое преобразование Неопределено -> Ложь в языке не предусмотрено, генерируется исключение: «Преобразование значения к типу Булево не может быть выполнено».

Посмотрим на примеры из практики:


// Пример 1: Ошибки не будет, так как вычисление остановится на первом шаге
Результат = Истина Или Неопределено; 

// Пример 2: Ошибка возникнет, так как системе нужно вычислить второй операнд
Результат = Ложь Или Неопределено; 

// Пример 3: Ошибка возникнет сразу
Результат = Неопределено Или Истина;

Как обеспечить стабильность кода (решения)

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

Способ 1. Явное сравнение с Истиной

Самый простой и читаемый способ — это всегда дописывать = Истина при проверке переменных, в которых вы не уверены. Проанализируем трансформацию кода:


// Было (опасно):
Флаг = РольДоступна("ПолныеПрава") Или П1 Или Ф1;

// Стало (безопасно):
Флаг = РольДоступна("ПолныеПрава") Или (П1 = Истина) Или (Ф1 = Истина);

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

Способ 2. Принудительное приведение типов

Мы можем воспользоваться конструктором типа Булево(). Это полезно, когда нужно гарантированно получить логический тип из неопределенных данных.


// Принудительно превращаем всё в Булево
Флаг = РольДоступна("ПолныеПрава") Или Булево(П1) Или Булево(Ф1);

Функция Булево(Неопределено) всегда возвращает Ложь. Аналогично она сработает и для числовых значений (0 станет Ложь, остальное — Истина).

Способ 3. Проверка на заполненность

Если логика вашего приложения подразумевает, что Неопределено — это отсутствие значения, которое нельзя трактовать как Ложь без предварительной проверки, используйте функцию ЗначениеЗаполнено().


Если ЗначениеЗаполнено(П1) Тогда
    // Здесь мы уверены, что П1 имеет смысл проверять
    Флаг = П1 Или Ф1;
КонецЕсли;

Различие между кодом и запросами

Важно не путать поведение кода во встроенном языке и поведение языка запросов 1С. В запросах (на уровне SQL) используется трехзначная логика. Если в запросе вы напишете ГДЕ Поле1 ИЛИ Поле2, и в одном из полей будет значение NULL, запрос не «упадет». Он вернет результат в соответствии с таблицами истинности SQL, где TRUE OR NULL = TRUE. Однако в программном коде 1С такая вольность недопустима.

Резюме

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

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

← На главную