К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как сравнить перечисление в 1С: все способы с примерами

Как сравнить значения перечисления в 1С: оператор равенства, ссылка в запросе, сравнение по имени и индексу. Примеры кода, типичные ошибки и FAQ.

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

Основная проблема в том, что значение перечисления — это не строка и не число, а ссылочный объект особого типа. Поэтому сравнение «Статус = "Закрыт"» не сработает так, как ожидает новичок: строка и ссылка на значение перечисления — разные типы, и сравнение даст ложь либо ошибку в зависимости от контекста. Правильно сравнивать значение перечисления с другим значением того же перечисления через менеджер объекта.

Ниже разобраны все рабочие способы сравнения: в коде на встроенном языке, в запросах, через имя и индекс значения, а также сравнение с пустой ссылкой. Отдельно рассмотрены типичные ошибки и способы проверить результат.

Как устроено перечисление и почему это важно для сравнения

Каждое значение перечисления хранится как предопределённая ссылка внутри конфигурации. У него есть три представления: имя (идентификатор, заданный в конфигураторе), синоним (представление для пользователя) и порядковый индекс внутри списка значений. При сравнении оператором «=» платформа сравнивает именно ссылки, а не строковые представления.

Из этого следует главное правило: сравнивать значение перечисления можно только со значением того же перечисления. Сравнение со значением другого перечисления всегда даст «Ложь», даже если имена совпадают. Сравнение со строкой, содержащей имя значения, — тоже «Ложь», потому что типы различаются.

Сравнение в коде через оператор равенства

Стандартный и рекомендуемый способ — сравнение через менеджер перечисления. Обращение вида Перечисления.СтатусыДокумента.Проведен возвращает ссылку на значение, и оператор «=» сравнивает её со значением реквизита или переменной.

Если Документ.Статус = Перечисления.СтатусыДокумента.Проведен Тогда

// действия для проведённого документа

КонецЕсли;

Для проверки на неравенство используйте оператор «<>». Если нужно проверить значение на вхождение в несколько вариантов, удобнее не цепочка условий «ИЛИ», а массив допустимых значений с методом Найти():

ДопустимыеСтатусы = Новый Массив;

ДопустимыеСтатусы.Добавить(Перечисления.Статусы.ВРаботе);

ДопустимыеСтатусы.Добавить(Перечисления.Статусы.НаСогласовании);

Если ДопустимыеСтатусы.Найти(ТекущийСтатус) <> Неопределено Тогда

// статус входит в список

КонецЕсли;

Такой подход легче расширять: при добавлении нового статуса достаточно дописать одну строку, а не переписывать условие.

bsl
Если Заказ.Статус = Перечисления.СтатусыЗаказа.Закрыт Тогда
	Возврат;
КонецЕсли;

Сравнение перечисления в запросе

В запросе сравнить значение перечисления можно двумя способами: через параметр и через литерал ЗНАЧЕНИЕ(). Первый способ универсальнее — значение передаётся из кода и запрос не нужно менять при изменении логики:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Заказы.Ссылка

|ИЗ

| Документ.ЗаказКлиента КАК Заказы

|ГДЕ

| Заказы.Статус = &Статус";

Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыЗаказа.ВРаботе);

Второй способ — литерал прямо в тексте запроса: ГДЕ Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказа.ВРаботе). Обратите внимание: в литерале используется единственное число «Перечисление», а не «Перечисления» как в коде модуля. Это частая причина синтаксической ошибки.

Для проверки на вхождение в список значений используйте оператор В (&СписокСтатусов), передав в параметр массив или список значений. Это эффективнее, чем несколько условий «ИЛИ», и корректно работает с индексами.

Сравнение по имени и через индекс значения

Иногда значение перечисления приходит извне — из файла обмена, веб-сервиса или строки, введённой пользователем. В этом случае строку сначала нужно преобразовать в значение перечисления, а уже потом сравнивать. Для поиска по имени используется индексация менеджера:

ИмяЗначения = "ВРаботе";

Если Метаданные.Перечисления.СтатусыЗаказа.ЗначенияПеречисления.Найти(ИмяЗначения) <> Неопределено Тогда

ЗначениеСтатуса = Перечисления.СтатусыЗаказа[ИмяЗначения];

КонецЕсли;

Предварительная проверка через метаданные обязательна: если имени нет в перечислении, обращение по индексу вызовет исключение. Для обратной задачи — получить имя значения, которое уже есть в переменной, — используется конструкция с XML-строкой или метод Индекс() в связке с метаданными:

ИндексЗначения = Перечисления.СтатусыЗаказа.Индекс(ТекущийСтатус);

ИмяЗначения = Метаданные.Перечисления.СтатусыЗаказа.ЗначенияПеречисления[ИндексЗначения].Имя;

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

Сравнение с пустой ссылкой перечисления

Реквизит типа «перечисление» может быть не заполнен — тогда он содержит пустую ссылку. Проверить это можно двумя способами. Первый — сравнение с пустой ссылкой через менеджер: Перечисления.СтатусыЗаказа.ПустаяСсылка(). Второй — функция ЗначениеЗаполнено(), которая вернёт «Ложь» для пустой ссылки.

Если Документ.Статус = Перечисления.СтатусыЗаказа.ПустаяСсылка() Тогда

// статус не задан

КонецЕсли;

Если НЕ ЗначениеЗаполнено(Документ.Статус) Тогда

// то же самое, но универсальнее

КонецЕсли;

В запросе пустая ссылка сравнивается через литерал ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказа.ПустаяСсылка). Имейте в виду: пустая ссылка перечисления не равна значению Неопределено — это разные состояния. Неопределено бывает у реквизитов составного типа, когда значение вообще не присвоено.

Как проверить, что сравнение работает правильно

После написания условия проверьте его на граничных случаях: заполненное значение, другое значение того же перечисления, пустая ссылка. Быстрый способ — временный вывод в сообщение или точка останова в отладчике с просмотром типа значения через ТипЗнч().

Полезный приём — вывести тип обеих сравниваемых величин. Если типы различаются (например, с одной стороны «Строка», с другой — «ПеречислениеСсылка»), причина несрабатывания условия найдена сразу.

Контрольные точки

Как проверить результат

Типы сравниваемых значений
Норма

Оба значения — ПеречислениеСсылка одного вида

Тревожный признак

Один из операндов — строка, число или другой тип

Значение реквизита в отладчике
Норма

Показывается значение перечисления или пустая ссылка

Тревожный признак

Неопределено там, где ожидалась пустая ссылка

Работа условия
Норма

Условие срабатывает на нужном значении и не срабатывает на других

Тревожный признак

Условие всегда ложно — вероятно, сравнение со строкой

Типичные ошибки при сравнении перечислений

Большинство проблем со сравнением перечислений сводится к нескольким повторяющимся сценариям. Их стоит проверять в первую очередь, если условие «не работает».

Типичные ошибки
01
Сравнение со строкой: Статус = "Закрыт" — всегда даёт Ложь, потому что строка не равна ссылке значения перечисления
02
Сравнение значений разных перечислений с одинаковыми именами — результат всегда Ложь, даже если имена совпадают
03
Обращение Перечисления.Имя[СтрокаИмени] без проверки через метаданные — исключение, если такого значения нет
04
Сравнение по синониму (представлению) — ломается при переименовании синонима в конфигураторе
05
Использование «Перечисления» во множественном числе внутри ЗНАЧЕНИЕ() в запросе — синтаксическая ошибка
06
Сравнение по индексу значения — логика молча ломается при изменении порядка значений

Ещё одна неочевидная ситуация — сравнение в динамическом списке или СКД. Там условия отбора по перечислению нужно строить через параметры компоновки, передавая именно значение перечисления, а не его представление. Пользовательский отбор по представлению может работать иначе, чем программный.

Итог

Что важно запомнить

Сравнивайте значения перечисления только со значениями того же перечисления через менеджер Перечисления.Имя.Значение. В запросах используйте параметры или ЗНАЧЕНИЕ(Перечисление.Имя.Значение). Пустую ссылку проверяйте через ПустаяСсылка() или ЗначениеЗаполнено(). Строки, индексы и синонимы для сравнения не используйте.

Частые вопросы о сравнении перечислений

Почему условие «Статус = "Закрыт"» никогда не срабатывает?

Потому что в кавычках указана строка, а реквизит хранит ссылку на значение перечисления. Это разные типы данных, и сравнение всегда возвращает «Ложь». Правильно: Статус = Перечисления.СтатусыДокумента.Закрыт.

Можно ли сравнить значения двух разных перечислений?

Технически оператор «=» выполнится, но результат всегда будет «Ложь», даже если имена значений совпадают. Если нужна такая логика, сопоставляйте значения через соответствие имён или отдельную таблицу соответствий.

Как проверить, что перечисление не заполнено?

Сравните реквизит с Перечисления.ИмяПеречисления.ПустаяСсылка() или используйте функцию ЗначениеЗаполнено() — она вернёт «Ложь» для пустой ссылки. Учтите, что пустая ссылка не равна Неопределено.

Как получить значение перечисления из строки с его именем?

Сначала проверьте существование значения через метаданные: Метаданные.Перечисления.Имя.ЗначенияПеречисления.Найти(ИмяСтрокой). Если значение найдено, получите его через Перечисления.Имя[ИмяСтрокой]. Без проверки обращение вызовет исключение.

Чем отличается сравнение в коде от сравнения в запросе?

В коде используется менеджер Перечисления.Имя.Значение (множественное число). В тексте запроса — литерал ЗНАЧЕНИЕ(Перечисление.Имя.Значение) в единственном числе, либо параметр запроса, в который значение передаётся из кода.

Можно ли сравнивать перечисления операторами «больше» или «меньше»?

Для значений перечисления такое сравнение не имеет практического смысла: порядок определяется расположением значений в конфигураторе и может измениться при доработке. Используйте только проверку на равенство, неравенство и вхождение в список.