Как исправить ошибку «Преобразование значения к типу Число не может быть выполнено» в 1С?

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

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

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

Анализ исходной ситуации: почему ломается код?

Рассмотрим пример кода, который вызвал затруднения у автора темы:


ВремКол = Строка.Количество;
Если Число(ВремКол) > Количество Тогда
    // Какая-то логика
КонецЕсли;

Автор утверждает, что в переменной ВремКол находится значение 50, и при выводе на экран отображается именно оно. Однако при сравнении платформа выдает ошибку преобразования. Давайте проанализируем эту ситуацию по шагам.

Когда мы пишем условие Число(ВремКол) > Количество, мы ожидаем, что сравниваются два числа. Ошибка преобразования может возникнуть в двух местах:

  1. В функции Число(ВремКол): если в переменной ВремКол находится строка, которую 1С не может распознать как число (например, строка с буквами, спецсимволами или пробелами), либо если там содержится значение типа NULL, Неопределено или объектная ссылка (например, пустая ссылка на справочник).
  2. В самом операторе сравнения >: если функция Число(ВремКол) отработала корректно и вернула число, но переменная Количество имеет тип, отличный от числа (например, Строка, NULL или Неопределено). В 1С нельзя сравнивать число напрямую с нечисловыми типами данных — это сразу вызывает ошибку типизации.

Глаза нас обманывают: разница между представлением и типом

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

Аналогично, если переменная содержит строковое значение "50 " (с пробелом на конце) или число 50, на экране они будут выглядеть одинаково. Однако попытка сравнить строку "50" с числом без явного преобразования приведет к ошибке.

Шаг 1. Точная диагностика с помощью отладчика

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

  1. Установим точку останова на строке с ошибкой (в нашем случае на строке с условием Если).
  2. Запустим сеанс в режиме отладки и дойдем до точки останова.
  3. Откроем табло (сочетание клавиш Ctrl + Alt + W) или воспользуемся быстрым вычислением выражения (Shift + F9).
  4. Проверим типы обеих переменных, используя встроенную функцию ТипЗнч().

В табло необходимо вычислить следующие выражения:


ТипЗнч(ВремКол)
ТипЗнч(Количество)

Только после этого мы увидим реальную картину. Очень часто оказывается, что ВремКол имеет тип Строка, а переменная Количество — это вообще Неопределено или NULL (особенно если данные заполнялись из запроса или загружались из внешнего источника).

Шаг 2. Борьба с NULL и Неопределено в запросах

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

Ни в коде, ни в запросе нельзя выполнять математические операции с NULL. Чтобы решить эту проблему на уровне запроса, всегда используйте функцию ЕСТЬNULL. Рассмотрим пример:


ВЫБРАТЬ
    ТоварыСклада.Номенклатура,
    ЕСТЬNULL(ОстаткиТоваров.КоличествоОстаток, 0) КАК Количество
ИЗ
    Справочник.Номенклатура КАК ТоварыСклада
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ОстаткиТоваров
    ПО ТоварыСклада.Ссылка = ОстаткиТоваров.Номенклатура

Использование ЕСТЬNULL(Поле, 0) гарантирует, что если остатка нет, то в выборку попадет число 0, а не пустое значение NULL. Это полностью исключит ошибку при последующей обработке данных в коде модуля.

Если же значение обрабатывается непосредственно в коде, мы можем сделать быструю проверку «на лету» перед сравнением:


ЧисловоеКоличество = ?(ЗначениеЗаполнено(Количество), Количество, 0);

Шаг 3. Очистка невидимых символов и пробелов

Если тип переменной действительно является строкой (например, "50"), но функция Число() все равно выдает ошибку, проблема кроется в скрытых невидимых символах. Особенно часто это происходит при импорте данных из Excel, XML или при парсинге веб-страниц.

Рассмотрим основные скрытые угрозы:

Для надежного преобразования строки в число напишем безопасную функцию очистки строки от «мусора»:


// Очищаем строку от неразрывных пробелов и обычных пробелов по краям
ОчищеннаяСтрока = СтрЗаменить(ВремКол, Символы.НПП, ""); // Удаляем неразрывные пробелы
ОчищеннаяСтрока = СокрЛП(ОчищеннаяСтрока);              // Удаляем обычные пробелы по краям

// Теперь преобразование пройдет успешно
ИтоговоеЧисло = Число(ОчищеннаяСтрока);

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


ОчищеннаяСтрока = СтрЗаменить(ОчищеннаяСтрока, ".", ",");

Опасный совет: почему нельзя использовать Попытка ... Исключение для обхода ошибки

В обсуждениях часто предлагают простое на первый взгляд решение — обернуть проблемный участок кода в конструкцию Попытка ... Исключение:


Попытка
    Если Число(ВремКол) > Количество Тогда
        // Логика
    КонецЕсли;
Исключение
    // Ошибку просто замалчиваем
КонецПопытки;

Внимание! Это крайне опасный подход, особенно если код выполняется внутри транзакции записи или проведения документа.

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

Поэтому всегда используйте явную предварительную проверку типов через Если ... Тогда вместо подавления ошибок через Попытка.

Рекомендуемый шаблон безопасного сравнения чисел

Давайте объединим все лучшие практики диагностики и исправления этой ошибки в один универсальный и отказоустойчивый шаблон кода:


// 1. Приводим первое значение к числу безопасно
Число1 = 0;
Если ТипЗнч(ВремКол) = Тип("Число") Тогда
    Число1 = ВремКол;
ИначеЕсли ТипЗнч(ВремКол) = Тип("Строка") Тогда
    // Очищаем строку от лишних символов
    СтрокаЧисла = СтрЗаменить(ВремКол, Символы.НПП, "");
    СтрокаЧисла = СтрЗаменить(СтрокаЧисла, " ", "");
    СтрокаЧисла = СтрЗаменить(СтрокаЧисла, ".", ",");
    СтрокаЧисла = СокрЛП(СтрокаЧисла);
    
    Попытка
        Число1 = Число(СтрокаЧисла);
    Исключение
        Число1 = 0; // Дефолтное значение, если строка совсем некорректная
    КонецПопытки;
КонецЕсли;

// 2. Приводим второе значение к числу безопасно
Число2 = 0;
Если ТипЗнч(Количество) = Тип("Число") Тогда
    Число2 = Количество;
ИначеЕсли ТипЗнч(Количество) = Тип("Строка") Тогда
    СтрокаЧисла = СтрЗаменить(Количество, Символы.НПП, "");
    СтрокаЧисла = СтрЗаменить(СтрокаЧисла, " ", "");
    СтрокаЧисла = СтрЗаменить(СтрокаЧисла, ".", ",");
    СтрокаЧисла = СокрЛП(СтрокаЧисла);
    
    Попытка
        Число2 = Число(СтрокаЧисла);
    Исключение
        Число2 = 0;
    КонецПопытки;
КонецЕсли;

// 3. Выполняем сравнение подготовленных числовых переменных
Если Число1 > Число2 Тогда
    // Ваша бизнес-логика, которая теперь никогда не упадет с ошибкой преобразования
КонецЕсли;

Применение такого подхода гарантирует стабильную работу вашей программы при любых входящих данных, будь то пустые строки, значения NULL из запросов или некорректно заполненные реквизиты в табличных частях документов.

← На главную