При разработке или доработке конфигураций на платформе 1С:Предприятие 8 программисты часто сталкиваются с ошибкой: «Преобразование значения к типу Булево не может быть выполнено». Эта проблема кажется тривиальной, но она вскрывает фундаментальные особенности типизации в языке 1С. В этой статье мы детально разберем, почему возникает эта ошибка на примере реального кейса с формой табеля учета рабочего времени, и как правильно писать код, чтобы избежать подобных ситуаций.
Рассмотрим ситуацию, представленную в вопросе автора. В программном коде формы документа при заполнении табличной части используется следующее условие:
ИначеЕсли Элементы.Табель.ПодчиненныеЭлементы.Найти("ТабельДень"+?(Лев(Строка(Стр.Дата),1)= "0",Сред(Строка(Стр.Дата),2,1),Лев(Строка(Стр.Дата),2))) Тогда
Давайте проанализируем, что здесь происходит. Программа пытается динамически найти элемент формы по его имени. Метод Найти() коллекции ПодчиненныеЭлементы (или любой другой коллекции в 1С, например, СтрокиТаблицыЗначений) возвращает один из двух вариантов:
Ошибка возникает из-за того, что в операторе Если...Тогда или ИначеЕсли...Тогда платформа ожидает строго значение типа Булево (либо Истина, либо Ложь). В отличие от таких языков, как JavaScript или C++, где объект может неявно трактоваться как "true", а null как "false", в 1С неявное преобразование типов для условий запрещено. Платформа не может решить, является ли найденный объект (например, поле формы) "истиной".
Самый простой и логичный способ исправить ошибку — это явно указать, что мы проверяем факт нахождения элемента. Если метод Найти() вернул что-то отличное от Неопределено, значит, элемент существует.
Исправленный код будет выглядеть так:
ИскомыйЭлемент = Элементы.Табель.ПодчиненныеЭлементы.Найти(ИмяЭлемента);
Если ИскомыйЭлемент <> Неопределено Тогда
// Логика, если элемент найден
КонецЕсли;
Применительно к исходному коду автора, условие должно быть записано следующим образом:
ИначеЕсли Элементы.Табель.ПодчиненныеЭлементы.Найти("ТабельДень" + ИмяДня) <> Неопределено Тогда
Профессиональным стандартом в среде 1С считается использование универсальной функции ЗначениеЗаполнено(). Она возвращает Истина, если переданное в нее значение не является пустым для своего типа (для ссылок — не пустая ссылка, для объектов — не Неопределено и не Null, для строк — не пустая строка).
Разберем пример реализации:
ИмяПоля = "ТабельДень" + Формат(День(Стр.Дата), "ЧГ=0");
Если ЗначениеЗаполнено(Элементы.Табель.ПодчиненныеЭлементы.Найти(ИмяПоля)) Тогда
// Элемент найден, выполняем действия
КонецЕсли;
Этот подход делает код более устойчивым и читаемым. Мы сразу понимаем, что нас интересует факт наличия "содержательного" значения в результате поиска.
Рассмотрим неудачные советы, которые прозвучали в обсуждении на форуме. Например, в сообщении №5 предлагается написать:
... = ИСТИНА Тогда
Почему это плохо: Если метод Найти() вернет объект (например, ГруппаФормы или ПолеФормы), сравнение Объект = Истина всегда будет давать результат Ложь, так как типы данных не совпадают. В итоге ошибка преобразования исчезнет, но условие перестанет выполняться вовсе, и логика программы будет нарушена. Система просто "проскочит" этот блок кода.
Проанализируем еще одну критическую ошибку в исходном коде: использование Строка(Стр.Дата) и функций Лев() / Сред() для получения номера дня. Это крайне опасный путь.
Выясним причину: результат функции Строка() для даты зависит от настроек операционной системы. На одном сервере дата может преобразоваться в "01.05.2023", а на другом — в "2023-05-01". В результате функции Лев() и Сред() вернут совершенно разные символы, и имя элемента "ТабельДень" + ... будет сформировано неправильно. Это приведет к тому, что Найти() всегда будет возвращать Неопределено, даже если визуально на форме всё в порядке.
Как делать правильно: Для получения числа из даты используйте встроенные функции платформы или форматирование.
День(Стр.Дата) — возвращает число от 1 до 31.Формат(Стр.Дата, "ДФ=д") — вернет номер дня в виде строки.Как справедливо отмечено в сообщении №26, не стоит писать "трехэтажные" условия внутри оператора Если. Это затрудняет отладку и чтение кода. Давайте разберем, как сделать этот участок кода эталонным:
// 1. Получаем номер дня безопасным способом
НомерДняСтрокой = Формат(Стр.Дата, "ДФ=д");
// 2. Формируем имя искомого элемента
ИмяНужногоЭлемента = "ТабельДень" + НомерДняСтрокой;
// 3. Пытаемся найти элемент
НайденныйЭлемент = Элементы.Табель.ПодчиненныеЭлементы.Найти(ИмяНужногоЭлемента);
// 4. Проверяем результат
Если НайденныйЭлемент <> Неопределено Тогда
// Теперь мы точно знаем, что элемент существует, и можем с ним работать
НайденныйЭлемент.Видимость = Истина;
КонецЕсли;
Такой подход позволяет в отладчике на каждом шаге проверить, какое имя сформировалось и был ли найден объект. Это экономит часы поиска ошибок при изменении структуры формы.
Автор темы указал, что после перезагрузки сервера ошибка временно исчезла. Проанализируем ситуацию. В 1С это часто связано с кэшированием метаданных. Если в конфигураторе были внесены изменения в форму (удалены или добавлены элементы), а у пользователя в сеансе остался старый кэш, обращение к коллекциям Элементы может вести себя непредсказуемо.
Однако, перезагрузка — это не решение программной ошибки. Как только программный поток дойдет до проблемного сотрудника или определенной даты, вызывающей выполнение ветки ИначеЕсли, ошибка вернется снова. Единственный надежный способ — исправление типизации в коде.
Чтобы больше не сталкиваться с ошибкой преобразования к Булево при поиске элементов, придерживайтесь следующих правил:
Найти() непосредственно в условие Если.Неопределено или используйте ЗначениеЗаполнено().Строка() для получения её частей, используйте специальные функции День(), Месяц(), Год().