Как проверить наличие значения перечисления в списке перечислений в условии "Если" в 1С?

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

При работе с платформой 1С:Предприятие 8 часто возникает задача проверки, принадлежит ли текущее значение перечисления определенному набору допустимых значений. Типичный сценарий — это создание условного оператора Если, в котором необходимо выяснить, входит ли выбранный тип из перечисления в заранее заданный список. Мы рассмотрим несколько эффективных и рекомендуемых способов решения этой задачи, избегая громоздких конструкций с многочисленными операторами ИЛИ.

Хотя в 1С отсутствует прямая конструкция вида Если Тип В (Перечисление.Типы.Тип1, Перечисление.Типы.Тип3) Тогда для списка литералов перечислений в одну строку, как это может быть реализовано в некоторых других языках программирования или в запросах 1С, мы можем достичь той же функциональности, используя различные объекты платформы. Эти методы позволяют сделать код чище, производительнее и легче для поддержки.

1. Использование объекта "СписокЗначений"

Объект СписокЗначений является одним из наиболее часто используемых и интуитивно понятных инструментов для хранения набора значений и последующей проверки их наличия. Мы можем создать экземпляр СпискаЗначений, добавить в него требуемые значения перечисления, а затем использовать метод НайтиПоЗначению() для проверки.

Шаг 1: Создание и заполнение СпискаЗначений.

В начале вашего модуля или функции, где требуется эта проверка, создайте новый объект СписокЗначений и заполните его необходимыми элементами перечисления. Это действие обычно выполняется один раз при инициализации или при первом использовании.


// Предположим, что у нас есть перечисление "Типы" со значениями "Тип1", "Тип2", "Тип3" и т.д.
// И переменная "ВыбранныйТип" содержит текущее значение перечисления.

// Создаем СписокЗначений
СписокДопустимыхТипов = Новый СписокЗначений;

// Добавляем нужные значения перечисления
СписокДопустимыхТипов.Добавить(Перечисления.Типы.Тип1);
СписокДопустимыхТипов.Добавить(Перечисления.Типы.Тип3);
СписокДопустимыхТипов.Добавить(Перечисления.Типы.Тип5);

Шаг 2: Проверка наличия значения.

После того как СписокДопустимыхТипов заполнен, мы можем выполнить проверку в условии Если, используя метод НайтиПоЗначению(). Этот метод возвращает найденный элемент списка (тип ЭлементСпискаЗначений) или Неопределено, если значение не найдено.


Если СписокДопустимыхТипов.НайтиПоЗначению(ВыбранныйТип) <> Неопределено Тогда
    // ВыбранныйТип входит в список допустимых
    Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
    // ВыбранныйТип не входит в список допустимых
    Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;

Преимущества данного подхода:

  1. Читабельность: Код становится значительно более читаемым, чем длинные цепочки ИЛИ.
  2. Производительность: Для небольших и средних списков значений метод НайтиПоЗначению() работает достаточно быстро.
  3. Гибкость: Список можно формировать динамически, добавляя или удаляя элементы в зависимости от логики программы.
  4. Типобезопасность: Мы работаем напрямую с объектами перечисления, что исключает ошибки преобразования типов.

2. Использование объекта "Соответствие"

Объект Соответствие (аналог словаря или хеш-таблицы в других языках) предоставляет еще один мощный способ для быстрой проверки наличия элемента. Он особенно эффективен, когда требуется очень высокая производительность для часто повторяющихся проверок больших списков, поскольку поиск по ключу осуществляется очень быстро (практически за константное время).

Шаг 1: Создание и заполнение Соответствия.

Мы создаем объект Соответствие, где ключами будут являться значения перечисления, а значениями — что угодно (например, булево Истина или просто Неопределено, если нас интересует только наличие ключа). Как и в случае со СпискомЗначений, заполнение производится один раз.


// Создаем Соответствие
СоответствиеДопустимыхТипов = Новый Соответствие;

// Заполняем Соответствие. Ключ - значение перечисления, Значение - любое (например, Истина)
СоответствиеДопустимыхТипов.Вставить(Перечисления.Типы.Тип1, Истина);
СоответствиеДопустимыхТипов.Вставить(Перечисления.Типы.Тино3, Истина);
СоответствиеДопустимыхТипов.Вставить(Перечисления.Типы.Тип5, Истина);

Шаг 2: Проверка наличия значения.

Проверка осуществляется путем попытки получить значение по ключу. Если ключ существует, метод Получить() вернет ассоциированное значение; если ключа нет, он вернет Неопределено. Также можно использовать синтаксис доступа к элементу по ключу через квадратные скобки.


// Вариант 1: Через метод Получить()
Если СоответствиеДопустимыхТипов.Получить(ВыбранныйТип) <> Неопределено Тогда
    Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
    Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;

// Вариант 2: Через квадратные скобки (более краткий, но может быть менее явным для новичков)
// Примечание: Если ключа нет, обращение Соответствие[ВыбранныйТип] также вернет Неопределено.
Если СоответствиеДопустимыхТипов[ВыбранныйТип] <> Неопределено Тогда
    Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
    Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;

Важно понимать, что при проверке Соответствие[Ключ] <> Неопределено мы предполагаем, что если ключ присутствует, его значение не является Неопределено. В данном случае, когда мы специально записываем Истина, это условие всегда выполняется. Если же в соответствии могут храниться значения Неопределено (что в общем случае допустимо), то для проверки *наличия ключа* лучше использовать метод Соответствие.Ключи().Найти(ВыбранныйТип) <> Неопределено, но это уже менее производительно и усложняет код.

Преимущества данного подхода:

  1. Высокая производительность: Для больших объемов данных Соответствие обеспечивает очень быстрый поиск.
  2. Гибкость: Возможность связывать ключи с любыми значениями позволяет использовать Соответствие для более сложных логических структур, не только для проверки наличия.
  3. Типобезопасность: Как и СписокЗначений, работает напрямую с объектами перечисления.

3. Преобразование в строковое представление

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

Шаг 1: Преобразование значения перечисления в строку.

Для преобразования значения перечисления в строку мы можем использовать функцию XMLСтрока(). Она возвращает полное строковое представление значения, включая имя перечисления и значение.


СтроковоеПредставлениеТипа = XMLСтрока(ВыбранныйТип); 
// Пример: "Перечисление.Типы.Тип1"

Шаг 2: Проверка наличия строки в списке.

Затем мы можем использовать функцию СтрРазделить() для создания массива строк из заранее заданной строки-списка, а затем метод Найти() этого массива для поиска нашего строкового представления.


// Определяем строку с допустимыми значениями перечисления, разделенными запятой
СтрокаДопустимыхТипов = "Перечисление.Типы.Тип1,Перечисление.Типы.Тип3,Перечисление.Типы.Тип5";

// Разделяем строку на массив
МассивДопустимыхТипов = СтрРазделить(СтрокаДопустимыхТипов, ",");

// Проверяем наличие строкового представления текущего типа в массиве
Если МассивДопустимыхТипов.Найти(XMLСтрока(ВыбранныйТип)) <> Неопределено Тогда
    Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
    Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;

В данном случае, если нам действительно нужно "одной строкой" (хотя это спорное утверждение, так как формирование массива происходит неявно), мы можем комбинировать:


// Пример "одной строкой", если допустить, что создание массива СтрРазделить происходит неявно
Если СтрРазделить("Перечисление.Типы.Тип1,Перечисление.Типы.Тип3,Перечисление.Типы.Тип5", ",").Найти(XMLСтрока(ВыбранныйТип)) <> Неопределено Тогда
    Сообщить("Выбранный тип находится в списке допустимых.");
Иначе
    Сообщить("Выбранный тип не находится в списке допустимых.");
КонецЕсли;

Недостатки данного подхода:

  1. Производительность: Преобразование типов и строковые операции могут быть медленнее, особенно для больших объемов данных или частых проверок.
  2. Типобезопасность: Работа со строками менее типобезопасна. Изменение имени перечисления или его значения в конфигурации потребует ручного обновления строковых констант.
  3. Ошибки: Человеческий фактор при ручном вводе строковых значений может привести к ошибкам (опечатки, пробелы).
  4. Неудобство: Если список значений большой, поддерживать его в виде длинной строки становится неудобно.

Несмотря на кажущуюся "однострочность" при жестко заданном списке, этот метод обычно менее предпочтителен для производительности и надежности по сравнению со СпискомЗначений или Соответствием.

4. Использование оператора "В" в запросах 1С

Если проверка необходима в контексте запроса к базе данных 1С, то для этой цели идеально подходит оператор В. Это наиболее "однострочный" и производительный способ для работы с наборами значений в запросах.

Шаг 1: Формирование списка параметров для запроса.

Для передачи списка значений перечисления в запрос, мы можем использовать массив или временную таблицу значений.


// Пример с массивом (для небольших списков)
МассивДопустимыхТиповЗапроса = Новый Массив;
МассивДопустимыхТиповЗапроса.Добавить(Перечисления.Типы.Тип1);
МассивДопустимыхТиповЗапроса.Добавить(Перечисления.Типы.Тип3);

// Пример с СписокЗначений (преобразуется в массив при передаче в запрос)
СписокДопустимыхТиповЗапроса = Новый СписокЗначений;
СписокДопустимыхТиповЗапроса.Добавить(Перечисления.Типы.Тип1);
СписокДопустимыхТиповЗапроса.Добавить(Перечисления.Типы.Тип3);

Шаг 2: Использование оператора "В" в запросе.

В тексте запроса мы используем оператор В с параметром, которому будет передан наш список значений.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ДокументСсылка.ВидПеречисления КАК ТекущийВид
    |ИЗ
    |    Документ.ПриходнаяНакладная КАК ДокументСсылка
    |ГДЕ
    |    ДокументСсылка.ВидПеречисления В (&СписокДопустимыхТипов)"; // &СписокДопустимыхТипов - параметр запроса

Запрос.УстановитьПараметр("СписокДопустимыхТипов", МассивДопустимыхТиповЗапроса); 
// Или Запрос.УстановитьПараметр("СписокДопустимыхТипов", СписокДопустимыхТиповЗапроса);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    Сообщить("Найден документ с допустимым типом: " + Выборка.ТекущийВид);
КонецЦикла;

Преимущества данного подхода:

  1. Оптимизация базы данных: Оператор В оптимизирован на уровне СУБД для эффективной работы с наборами значений.
  2. Ясность: Синтаксис В очень понятен и лаконичен.
  3. Высокая производительность: Для фильтрации больших объемов данных в базе этот метод является наиболее производительным.

5. Работа с метаданными системы

Этот подход используется в более динамических сценариях, когда список допустимых значений перечисления может меняться или зависит от анализа структуры метаданных конфигурации. Например, если нам нужно проверить, является ли значение перечисления одним из *всех возможных* значений перечисления, или если мы хотим получить значения, удовлетворяющие какому-либо условию из метаданных.

Шаг 1: Получение объекта метаданных перечисления.

Мы обращаемся к коллекции Метаданные.Перечисления и по имени получаем нужное перечисление.


// Получаем объект метаданных перечисления "Типы"
ОбъектМетаданныхПеречисления = Метаданные.Перечисления.Типы;

Шаг 2: Итерация по значениям перечисления или их фильтрация.

Коллекция ОбъектМетаданныхПеречисления.Значения содержит все предопределенные значения данного перечисления. Мы можем пройтись по ним или преобразовать их в СписокЗначений/Соответствие для дальнейшей работы.


// Пример: Создание списка значений из всех значений перечисления
ВсеЗначенияПеречисленияСписок = Новый СписокЗначений;
Для Каждого ЗначениеМетаданных Из ОбъектМетаданныхПеречисления.Значения Цикл
    ВсеЗначенияПеречисленияСписок.Добавить(ЗначениеМетаданных.Имя); // Добавляем имя как строку
    // Или, если нужно само значение перечисления, можно получить его через ЗначениеПеречисления.Получить()
    // Например, ВсеЗначенияПеречисленияСписок.Добавить(Перечисления.Типы[ЗначениеМетаданных.Имя]);
КонецЦикла;

// Затем можно проверять наличие, как в первом способе:
Если ВсеЗначенияПеречисленияСписок.НайтиПоЗначению(ВыбранныйТип) <> Неопределено Тогда
    Сообщить("Выбранный тип существует в метаданных.");
КонецЕсли;

// Пример использования имени значения для более специфичных условий
// (из сообщения 23, адаптировано)
// Если в метаданных есть какой-то признак для значения перечисления
Для Каждого ЗначениеМетаданных Из ОбъектМетаданныхПеречисления.Значения Цикл
    Если ЗначениеМетаданных.Имя = "Прочий" Тогда
        // С этим значением что-то делаем
        Сообщить("Найден тип 'Прочий'.");
    КонецЕсли;
КонецЦикла;

Преимущества данного подхода:

  1. Динамичность: Позволяет адаптироваться к изменениям конфигурации без изменения кода.
  2. Гибкость: Дает возможность строить сложную логику на основе анализа метаданных.

Недостатки:

  1. Избыточность: Для простой проверки на вхождение в статический набор значений этот метод избыточен и менее производителен, чем прямая работа со СпискомЗначений или Соответствием.
  2. Сложность: Код становится сложнее из-за работы с объектами метаданных.

Заключение

Мы рассмотрели несколько подходов к проверке наличия значения перечисления в списке в 1С. Каждый из них имеет свои преимущества и недостатки, и выбор оптимального решения зависит от конкретных требований вашей задачи:

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

← На главную