При работе с платформой 1С:Предприятие 8 часто возникает задача проверки, принадлежит ли текущее значение перечисления определенному набору допустимых значений. Типичный сценарий — это создание условного оператора Если, в котором необходимо выяснить, входит ли выбранный тип из перечисления в заранее заданный список. Мы рассмотрим несколько эффективных и рекомендуемых способов решения этой задачи, избегая громоздких конструкций с многочисленными операторами ИЛИ.
Хотя в 1С отсутствует прямая конструкция вида Если Тип В (Перечисление.Типы.Тип1, Перечисление.Типы.Тип3) Тогда для списка литералов перечислений в одну строку, как это может быть реализовано в некоторых других языках программирования или в запросах 1С, мы можем достичь той же функциональности, используя различные объекты платформы. Эти методы позволяют сделать код чище, производительнее и легче для поддержки.
Объект СписокЗначений является одним из наиболее часто используемых и интуитивно понятных инструментов для хранения набора значений и последующей проверки их наличия. Мы можем создать экземпляр СпискаЗначений, добавить в него требуемые значения перечисления, а затем использовать метод НайтиПоЗначению() для проверки.
Шаг 1: Создание и заполнение СпискаЗначений.
В начале вашего модуля или функции, где требуется эта проверка, создайте новый объект СписокЗначений и заполните его необходимыми элементами перечисления. Это действие обычно выполняется один раз при инициализации или при первом использовании.
// Предположим, что у нас есть перечисление "Типы" со значениями "Тип1", "Тип2", "Тип3" и т.д.
// И переменная "ВыбранныйТип" содержит текущее значение перечисления.
// Создаем СписокЗначений
СписокДопустимыхТипов = Новый СписокЗначений;
// Добавляем нужные значения перечисления
СписокДопустимыхТипов.Добавить(Перечисления.Типы.Тип1);
СписокДопустимыхТипов.Добавить(Перечисления.Типы.Тип3);
СписокДопустимыхТипов.Добавить(Перечисления.Типы.Тип5);
Шаг 2: Проверка наличия значения.
После того как СписокДопустимыхТипов заполнен, мы можем выполнить проверку в условии Если, используя метод НайтиПоЗначению(). Этот метод возвращает найденный элемент списка (тип ЭлементСпискаЗначений) или Неопределено, если значение не найдено.
Если СписокДопустимыхТипов.НайтиПоЗначению(ВыбранныйТип) <> Неопределено Тогда
// ВыбранныйТип входит в список допустимых
Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
// ВыбранныйТип не входит в список допустимых
Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;
Преимущества данного подхода:
ИЛИ.НайтиПоЗначению() работает достаточно быстро.Объект Соответствие (аналог словаря или хеш-таблицы в других языках) предоставляет еще один мощный способ для быстрой проверки наличия элемента. Он особенно эффективен, когда требуется очень высокая производительность для часто повторяющихся проверок больших списков, поскольку поиск по ключу осуществляется очень быстро (практически за константное время).
Шаг 1: Создание и заполнение Соответствия.
Мы создаем объект Соответствие, где ключами будут являться значения перечисления, а значениями — что угодно (например, булево Истина или просто Неопределено, если нас интересует только наличие ключа). Как и в случае со СпискомЗначений, заполнение производится один раз.
// Создаем Соответствие
СоответствиеДопустимыхТипов = Новый Соответствие;
// Заполняем Соответствие. Ключ - значение перечисления, Значение - любое (например, Истина)
СоответствиеДопустимыхТипов.Вставить(Перечисления.Типы.Тип1, Истина);
СоответствиеДопустимыхТипов.Вставить(Перечисления.Типы.Тино3, Истина);
СоответствиеДопустимыхТипов.Вставить(Перечисления.Типы.Тип5, Истина);
Шаг 2: Проверка наличия значения.
Проверка осуществляется путем попытки получить значение по ключу. Если ключ существует, метод Получить() вернет ассоциированное значение; если ключа нет, он вернет Неопределено. Также можно использовать синтаксис доступа к элементу по ключу через квадратные скобки.
// Вариант 1: Через метод Получить()
Если СоответствиеДопустимыхТипов.Получить(ВыбранныйТип) <> Неопределено Тогда
Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;
// Вариант 2: Через квадратные скобки (более краткий, но может быть менее явным для новичков)
// Примечание: Если ключа нет, обращение Соответствие[ВыбранныйТип] также вернет Неопределено.
Если СоответствиеДопустимыхТипов[ВыбранныйТип] <> Неопределено Тогда
Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;
Важно понимать, что при проверке Соответствие[Ключ] <> Неопределено мы предполагаем, что если ключ присутствует, его значение не является Неопределено. В данном случае, когда мы специально записываем Истина, это условие всегда выполняется. Если же в соответствии могут храниться значения Неопределено (что в общем случае допустимо), то для проверки *наличия ключа* лучше использовать метод Соответствие.Ключи().Найти(ВыбранныйТип) <> Неопределено, но это уже менее производительно и усложняет код.
Преимущества данного подхода:
Соответствие обеспечивает очень быстрый поиск.Соответствие для более сложных логических структур, не только для проверки наличия.СписокЗначений, работает напрямую с объектами перечисления.Этот метод основан на преобразовании значения перечисления в строку и последующей проверке вхождения этой строки в другой строковый список или массив строк. Это один из способов, который может быть записан более "одной строкой" для проверки, если список допустимых значений жестко закодирован в виде строки.
Шаг 1: Преобразование значения перечисления в строку.
Для преобразования значения перечисления в строку мы можем использовать функцию XMLСтрока(). Она возвращает полное строковое представление значения, включая имя перечисления и значение.
СтроковоеПредставлениеТипа = XMLСтрока(ВыбранныйТип);
// Пример: "Перечисление.Типы.Тип1"
Шаг 2: Проверка наличия строки в списке.
Затем мы можем использовать функцию СтрРазделить() для создания массива строк из заранее заданной строки-списка, а затем метод Найти() этого массива для поиска нашего строкового представления.
// Определяем строку с допустимыми значениями перечисления, разделенными запятой
СтрокаДопустимыхТипов = "Перечисление.Типы.Тип1,Перечисление.Типы.Тип3,Перечисление.Типы.Тип5";
// Разделяем строку на массив
МассивДопустимыхТипов = СтрРазделить(СтрокаДопустимыхТипов, ",");
// Проверяем наличие строкового представления текущего типа в массиве
Если МассивДопустимыхТипов.Найти(XMLСтрока(ВыбранныйТип)) <> Неопределено Тогда
Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;
В данном случае, если нам действительно нужно "одной строкой" (хотя это спорное утверждение, так как формирование массива происходит неявно), мы можем комбинировать:
// Пример "одной строкой", если допустить, что создание массива СтрРазделить происходит неявно
Если СтрРазделить("Перечисление.Типы.Тип1,Перечисление.Типы.Тип3,Перечисление.Типы.Тип5", ",").Найти(XMLСтрока(ВыбранныйТип)) <> Неопределено Тогда
Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;
Недостатки данного подхода:
Несмотря на кажущуюся "однострочность" при жестко заданном списке, этот метод обычно менее предпочтителен для производительности и надежности по сравнению со СпискомЗначений или Соответствием.
Если проверка необходима в контексте запроса к базе данных 1С, то для этой цели идеально подходит оператор В. Это наиболее "однострочный" и производительный способ для работы с наборами значений в запросах.
Шаг 1: Формирование списка параметров для запроса.
Для передачи списка значений перечисления в запрос, мы можем использовать массив или временную таблицу значений.
// Пример с массивом (для небольших списков)
МассивДопустимыхТиповЗапроса = Новый Массив;
МассивДопустимыхТиповЗапроса.Добавить(Перечисления.Типы.Тип1);
МассивДопустимыхТиповЗапроса.Добавить(Перечисления.Типы.Тип3);
// Пример с СписокЗначений (преобразуется в массив при передаче в запрос)
СписокДопустимыхТиповЗапроса = Новый СписокЗначений;
СписокДопустимыхТиповЗапроса.Добавить(Перечисления.Типы.Тип1);
СписокДопустимыхТиповЗапроса.Добавить(Перечисления.Типы.Тип3);
Шаг 2: Использование оператора "В" в запросе.
В тексте запроса мы используем оператор В с параметром, которому будет передан наш список значений.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДокументСсылка.ВидПеречисления КАК ТекущийВид
|ИЗ
| Документ.ПриходнаяНакладная КАК ДокументСсылка
|ГДЕ
| ДокументСсылка.ВидПеречисления В (&СписокДопустимыхТипов)"; // &СписокДопустимыхТипов - параметр запроса
Запрос.УстановитьПараметр("СписокДопустимыхТипов", МассивДопустимыхТиповЗапроса);
// Или Запрос.УстановитьПараметр("СписокДопустимыхТипов", СписокДопустимыхТиповЗапроса);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Найден документ с допустимым типом: " + Выборка.ТекущийВид);
КонецЦикла;
Преимущества данного подхода:
В оптимизирован на уровне СУБД для эффективной работы с наборами значений.В очень понятен и лаконичен.Этот подход используется в более динамических сценариях, когда список допустимых значений перечисления может меняться или зависит от анализа структуры метаданных конфигурации. Например, если нам нужно проверить, является ли значение перечисления одним из *всех возможных* значений перечисления, или если мы хотим получить значения, удовлетворяющие какому-либо условию из метаданных.
Шаг 1: Получение объекта метаданных перечисления.
Мы обращаемся к коллекции Метаданные.Перечисления и по имени получаем нужное перечисление.
// Получаем объект метаданных перечисления "Типы"
ОбъектМетаданныхПеречисления = Метаданные.Перечисления.Типы;
Шаг 2: Итерация по значениям перечисления или их фильтрация.
Коллекция ОбъектМетаданныхПеречисления.Значения содержит все предопределенные значения данного перечисления. Мы можем пройтись по ним или преобразовать их в СписокЗначений/Соответствие для дальнейшей работы.
// Пример: Создание списка значений из всех значений перечисления
ВсеЗначенияПеречисленияСписок = Новый СписокЗначений;
Для Каждого ЗначениеМетаданных Из ОбъектМетаданныхПеречисления.Значения Цикл
ВсеЗначенияПеречисленияСписок.Добавить(ЗначениеМетаданных.Имя); // Добавляем имя как строку
// Или, если нужно само значение перечисления, можно получить его через ЗначениеПеречисления.Получить()
// Например, ВсеЗначенияПеречисленияСписок.Добавить(Перечисления.Типы[ЗначениеМетаданных.Имя]);
КонецЦикла;
// Затем можно проверять наличие, как в первом способе:
Если ВсеЗначенияПеречисленияСписок.НайтиПоЗначению(ВыбранныйТип) <> Неопределено Тогда
Сообщить("Выбранный тип существует в метаданных.");
КонецЕсли;
// Пример использования имени значения для более специфичных условий
// (из сообщения 23, адаптировано)
// Если в метаданных есть какой-то признак для значения перечисления
Для Каждого ЗначениеМетаданных Из ОбъектМетаданныхПеречисления.Значения Цикл
Если ЗначениеМетаданных.Имя = "Прочий" Тогда
// С этим значением что-то делаем
Сообщить("Найден тип 'Прочий'.");
КонецЕсли;
КонецЦикла;
Преимущества данного подхода:
Недостатки:
СпискомЗначений или Соответствием.Мы рассмотрели несколько подходов к проверке наличия значения перечисления в списке в 1С. Каждый из них имеет свои преимущества и недостатки, и выбор оптимального решения зависит от конкретных требований вашей задачи:
СписокЗначений является наиболее сбалансированным решением по читаемости, производительности и удобству.Соответствие.В.Выбирая подходящий метод, всегда оценивайте частоту выполнения проверки, размер списка значений и требования к производительности и гибкости вашего кода.