Разработка и Конфигурация · 10 мин
Как сравнить перечисление в 1С: все способы с примерами
Как сравнить значения перечисления в 1С: оператор равенства, ссылка в запросе, сравнение по имени и индексу. Примеры кода, типичные ошибки и FAQ.
Перечисление в 1С — это предопределённый тип данных с фиксированным набором значений, заданным в конфигураторе. Сравнение значений перечисления — одна из самых частых операций в коде модулей: проверка статуса документа, вида операции, состояния заказа. При этом у разработчиков регулярно возникают вопросы: можно ли сравнивать перечисление со строкой, как сравнить его в запросе, что делать с пустой ссылкой.
Основная проблема в том, что значение перечисления — это не строка и не число, а ссылочный объект особого типа. Поэтому сравнение «Статус = "Закрыт"» не сработает так, как ожидает новичок: строка и ссылка на значение перечисления — разные типы, и сравнение даст ложь либо ошибку в зависимости от контекста. Правильно сравнивать значение перечисления с другим значением того же перечисления через менеджер объекта.
Ниже разобраны все рабочие способы сравнения: в коде на встроенном языке, в запросах, через имя и индекс значения, а также сравнение с пустой ссылкой. Отдельно рассмотрены типичные ошибки и способы проверить результат.
Как устроено перечисление и почему это важно для сравнения
Каждое значение перечисления хранится как предопределённая ссылка внутри конфигурации. У него есть три представления: имя (идентификатор, заданный в конфигураторе), синоним (представление для пользователя) и порядковый индекс внутри списка значений. При сравнении оператором «=» платформа сравнивает именно ссылки, а не строковые представления.
Из этого следует главное правило: сравнивать значение перечисления можно только со значением того же перечисления. Сравнение со значением другого перечисления всегда даст «Ложь», даже если имена совпадают. Сравнение со строкой, содержащей имя значения, — тоже «Ложь», потому что типы различаются.
Сравнение в коде через оператор равенства
Стандартный и рекомендуемый способ — сравнение через менеджер перечисления. Обращение вида Перечисления.СтатусыДокумента.Проведен возвращает ссылку на значение, и оператор «=» сравнивает её со значением реквизита или переменной.
Если Документ.Статус = Перечисления.СтатусыДокумента.Проведен Тогда
// действия для проведённого документа
КонецЕсли;
Для проверки на неравенство используйте оператор «<>». Если нужно проверить значение на вхождение в несколько вариантов, удобнее не цепочка условий «ИЛИ», а массив допустимых значений с методом Найти():
ДопустимыеСтатусы = Новый Массив;
ДопустимыеСтатусы.Добавить(Перечисления.Статусы.ВРаботе);
ДопустимыеСтатусы.Добавить(Перечисления.Статусы.НаСогласовании);
Если ДопустимыеСтатусы.Найти(ТекущийСтатус) <> Неопределено Тогда
// статус входит в список
КонецЕсли;
Такой подход легче расширять: при добавлении нового статуса достаточно дописать одну строку, а не переписывать условие.
Если Заказ.Статус = Перечисления.СтатусыЗаказа.Закрыт Тогда
Возврат;
КонецЕсли;Сравнение перечисления в запросе
В запросе сравнить значение перечисления можно двумя способами: через параметр и через литерал ЗНАЧЕНИЕ(). Первый способ универсальнее — значение передаётся из кода и запрос не нужно менять при изменении логики:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказы.Ссылка
|ИЗ
| Документ.ЗаказКлиента КАК Заказы
|ГДЕ
| Заказы.Статус = &Статус";
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыЗаказа.ВРаботе);
Второй способ — литерал прямо в тексте запроса: ГДЕ Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказа.ВРаботе). Обратите внимание: в литерале используется единственное число «Перечисление», а не «Перечисления» как в коде модуля. Это частая причина синтаксической ошибки.
Для проверки на вхождение в список значений используйте оператор В (&СписокСтатусов), передав в параметр массив или список значений. Это эффективнее, чем несколько условий «ИЛИ», и корректно работает с индексами.
Сравнение по имени и через индекс значения
Иногда значение перечисления приходит извне — из файла обмена, веб-сервиса или строки, введённой пользователем. В этом случае строку сначала нужно преобразовать в значение перечисления, а уже потом сравнивать. Для поиска по имени используется индексация менеджера:
ИмяЗначения = "ВРаботе";
Если Метаданные.Перечисления.СтатусыЗаказа.ЗначенияПеречисления.Найти(ИмяЗначения) <> Неопределено Тогда
ЗначениеСтатуса = Перечисления.СтатусыЗаказа[ИмяЗначения];
КонецЕсли;
Предварительная проверка через метаданные обязательна: если имени нет в перечислении, обращение по индексу вызовет исключение. Для обратной задачи — получить имя значения, которое уже есть в переменной, — используется конструкция с XML-строкой или метод Индекс() в связке с метаданными:
ИндексЗначения = Перечисления.СтатусыЗаказа.Индекс(ТекущийСтатус);
ИмяЗначения = Метаданные.Перечисления.СтатусыЗаказа.ЗначенияПеречисления[ИндексЗначения].Имя;
Сравнивать значения через индексы напрямую не стоит: порядок значений в конфигураторе может измениться при доработке, и логика молча сломается. Индекс — инструмент для получения имени, а не для сравнения.
Сравнение с пустой ссылкой перечисления
Реквизит типа «перечисление» может быть не заполнен — тогда он содержит пустую ссылку. Проверить это можно двумя способами. Первый — сравнение с пустой ссылкой через менеджер: Перечисления.СтатусыЗаказа.ПустаяСсылка(). Второй — функция ЗначениеЗаполнено(), которая вернёт «Ложь» для пустой ссылки.
Если Документ.Статус = Перечисления.СтатусыЗаказа.ПустаяСсылка() Тогда
// статус не задан
КонецЕсли;
Если НЕ ЗначениеЗаполнено(Документ.Статус) Тогда
// то же самое, но универсальнее
КонецЕсли;
В запросе пустая ссылка сравнивается через литерал ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказа.ПустаяСсылка). Имейте в виду: пустая ссылка перечисления не равна значению Неопределено — это разные состояния. Неопределено бывает у реквизитов составного типа, когда значение вообще не присвоено.
Как проверить, что сравнение работает правильно
После написания условия проверьте его на граничных случаях: заполненное значение, другое значение того же перечисления, пустая ссылка. Быстрый способ — временный вывод в сообщение или точка останова в отладчике с просмотром типа значения через ТипЗнч().
Полезный приём — вывести тип обеих сравниваемых величин. Если типы различаются (например, с одной стороны «Строка», с другой — «ПеречислениеСсылка»), причина несрабатывания условия найдена сразу.
Как проверить результат
Оба значения — ПеречислениеСсылка одного вида
Один из операндов — строка, число или другой тип
Показывается значение перечисления или пустая ссылка
Неопределено там, где ожидалась пустая ссылка
Условие срабатывает на нужном значении и не срабатывает на других
Условие всегда ложно — вероятно, сравнение со строкой
Типичные ошибки при сравнении перечислений
Большинство проблем со сравнением перечислений сводится к нескольким повторяющимся сценариям. Их стоит проверять в первую очередь, если условие «не работает».
Ещё одна неочевидная ситуация — сравнение в динамическом списке или СКД. Там условия отбора по перечислению нужно строить через параметры компоновки, передавая именно значение перечисления, а не его представление. Пользовательский отбор по представлению может работать иначе, чем программный.
Что важно запомнить
Сравнивайте значения перечисления только со значениями того же перечисления через менеджер Перечисления.Имя.Значение. В запросах используйте параметры или ЗНАЧЕНИЕ(Перечисление.Имя.Значение). Пустую ссылку проверяйте через ПустаяСсылка() или ЗначениеЗаполнено(). Строки, индексы и синонимы для сравнения не используйте.
Частые вопросы о сравнении перечислений
Почему условие «Статус = "Закрыт"» никогда не срабатывает?
Потому что в кавычках указана строка, а реквизит хранит ссылку на значение перечисления. Это разные типы данных, и сравнение всегда возвращает «Ложь». Правильно: Статус = Перечисления.СтатусыДокумента.Закрыт.
Можно ли сравнить значения двух разных перечислений?
Технически оператор «=» выполнится, но результат всегда будет «Ложь», даже если имена значений совпадают. Если нужна такая логика, сопоставляйте значения через соответствие имён или отдельную таблицу соответствий.
Как проверить, что перечисление не заполнено?
Сравните реквизит с Перечисления.ИмяПеречисления.ПустаяСсылка() или используйте функцию ЗначениеЗаполнено() — она вернёт «Ложь» для пустой ссылки. Учтите, что пустая ссылка не равна Неопределено.
Как получить значение перечисления из строки с его именем?
Сначала проверьте существование значения через метаданные: Метаданные.Перечисления.Имя.ЗначенияПеречисления.Найти(ИмяСтрокой). Если значение найдено, получите его через Перечисления.Имя[ИмяСтрокой]. Без проверки обращение вызовет исключение.
Чем отличается сравнение в коде от сравнения в запросе?
В коде используется менеджер Перечисления.Имя.Значение (множественное число). В тексте запроса — литерал ЗНАЧЕНИЕ(Перечисление.Имя.Значение) в единственном числе, либо параметр запроса, в который значение передаётся из кода.
Можно ли сравнивать перечисления операторами «больше» или «меньше»?
Для значений перечисления такое сравнение не имеет практического смысла: порядок определяется расположением значений в конфигураторе и может измениться при доработке. Используйте только проверку на равенство, неравенство и вхождение в список.