Рано или поздно каждый разработчик в среде «1С:Предприятие» сталкивается с ошибкой «Преобразование значения к типу Булево не может быть выполнено». Эта проблема является одной из самых частых во встроенном языке. Она мгновенно останавливает работу сеанса пользователя и вызывает аварийное завершение процедуры.
В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем поведение платформы 1С при неявном приведении типов, рассмотрим пример с форума и изучим самые надежные и профессиональные паттерны написания кода, которые позволят раз и навсегда предотвратить эту проблему.
Для начала давайте разберемся с технической логикой работы платформы 1С. В отличие от таких гибких веб-языков, как JavaScript или PHP, во встроенном языке 1С нет концепции так называемых «правдоподобных» (truthy) и «ложных» (falsy) значений для большинства типов данных.
Что это значит на практике? Если в JavaScript мы можем написать конструкцию if (myVariable), и она успешно выполнится, даже если в переменной находится объект, строка или пустое значение, то в 1С этот фокус не пройдет. Платформа 1С требует, чтобы в логическом условии (будь то оператор Если ... Тогда или тернарный оператор ?()) строго находилось значение логического типа — либо Истина, либо Ложь.
Платформа не умеет автоматически (неявно) приводить к типу Булево следующие типы данных:
Неопределено — значение по умолчанию для неинициализированных переменных или незаполненных реквизитов.NULL — значение, приходящее из баз данных (например, при левом соединении в запросах).Справочники.Номенклатура.ПустаяСсылка()). Единственное исключение разработчики платформы сделали для типа Число: число 0 неявно приводится к значению Ложь, а любое другое число — к Истина. Однако писать код с расчетом на эту особенность крайне не рекомендуется, так как это снижает его читаемость и усложняет аудит.
Если в логический оператор передается любое из перечисленных выше некорректных значений, выполнение программы прерывается с ошибкой преобразования.
Рассмотрим реальный пример, с которым столкнулся автор темы на форуме. В модуле формы обработки «Печать этикеток» на строке 112 возникает сбой:
ЭтикеткаОбласть.Параметры.Артикул = СтрокаИзСписка.Номенклатура.Артикул + ?(Демо, "-DEMO", "");
На первый взгляд, код выглядит вполне логично. Переменная Демо должна содержать булевский флаг (да или нет), который определяет, нужно ли добавлять суффикс "-DEMO" к артикулу. Однако в процессе работы в какой-то момент времени в переменную Демо попадает значение другого типа — чаще всего Неопределено.
Это может произойти по нескольким причинам:
Демо).Неопределено.Когда управление доходит до тернарного оператора ?(), платформа пытается вычислить первый параметр. Видя там Неопределено вместо ожидавшегося Истина или Ложь, 1С аварийно завершает работу.
Рассмотрим подробнее по шагам, как мы можем обезопасить наш код и обойти эту ошибку.
Это наиболее лаконичный и профессиональный вариант решения проблемы. Мы модифицируем условие внутри тернарного оператора следующим образом:
ЭтикеткаОбласть.Параметры.Артикул = СтрокаИзСписка.Номенклатура.Артикул + ?(Демо = Истина, "-DEMO", "");
Давайте проанализируем, почему этот простой прием гарантирует стабильность работы программы:
Истина абсолютно безопасно и никогда не вызывает ошибку приведения типов.Демо содержит Неопределено, операция сравнения Неопределено = Истина вернет системное значение Ложь.NULL, сравнение NULL = Истина также вернет Ложь.Ложь.Таким образом, результатом выражения Демо = Истина всегда гарантированно будет чистое булево значение. Тернарный оператор ?() выполнится корректно при любых обстоятельствах.
Если мы хотим сохранить исходную лаконичную запись тернарного оператора, нам необходимо гарантировать, что переменная Демо точно содержит булевский тип перед выводом этикетки. Для этого мы можем добавить блок предварительной проверки:
Если Демо = Неопределено Тогда
Демо = Ложь;
КонецЕсли;
ЭтикеткаОбласть.Параметры.Артикул = СтрокаИзСписка.Номенклатура.Артикул + ?(Демо, "-DEMO", "");
Этот способ хорош тем, что он явно документирует намерение разработчика в коде. Однако он требует написания дополнительных строк кода и не защищает от ситуации, если в переменной окажется не Неопределено, а, например, тип NULL.
В некоторых случаях (например, при написании сложных внешних обработок, которые должны работать в любых конфигурациях без сбоев) имеет смысл написать избыточный, но абсолютно «бронебойный» код с полной проверкой типов.
Проанализируем этот подход на примере следующего алгоритма:
ПрефиксАртикула = "";
Если ЗначениеЗаполнено(СтрокаИзСписка.Номенклатура.Артикул) Тогда
ПрефиксАртикула = Строка(СтрокаИзСписка.Номенклатура.Артикул);
КонецЕсли;
СуффиксАртикула = "";
Если ТипЗнч(Демо) = Тип("Булево") Тогда
Если Демо Тогда
СуффиксАртикула = "-DEMO";
КонецЕсли;
КонецЕсли;
ЭтикеткаОбласть.Параметры.Артикул = ПрефиксАртикула + СуффиксАртикула;
В данном случае мы разделяем формирование артикула на безопасные составляющие:
Строка(), защищаясь от возможных пустых ссылок или неопределенных значений в базе данных.Демо с помощью функции ТипЗнч(). Только если тип строго совпадает с системным типом Булево, мы позволяем программе проанализировать логическое условие внутри переменной.Пытаясь исправить эту ошибку самостоятельно, начинающие разработчики часто совершают две типичные ошибки, используя стандартные функции платформы:
1. Ловушка функции ЗначениеЗаполнено()
Иногда в коде можно встретить следующую попытку проверки флага: Если ЗначениеЗаполнено(Демо) Тогда.... Будьте осторожны! Во встроенном языке 1С вызов ЗначениеЗаполнено(Ложь) возвращает Истина. Платформа считает системное значение Ложь полностью определенным и заполненным логическим значением (в отличие от пустой строки или Неопределено). Использование этой функции для проверки булевых переменных приведет к логическим ошибкам в работе программы.
2. Ограниченность функции приведения типов Булево()
В 1С существует функция явного преобразования типов Булево(). Но она не спасет вас, если вы передадите в нее пустое значение. При попытке выполнить Булево(Неопределено) или Булево(NULL) платформа выбросит точно такую же ошибку времени выполнения. Эта функция предназначена в основном для преобразования чисел (например, Булево(1) вернет Истина) или строковых значений "Истина"/"Ложь".
Для предотвращения ошибок приведения типов придерживайтесь простых правил совместной работы с логическими выражениями в 1С:
Если МояПеременная = Истина Тогда вместо короткого Если МояПеременная Тогда. Это убережет код от падений, если переменная окажется пустой.ЕСТЬNULL(ИмяПоля, Ложь) непосредственно в тексте запроса.