Довольно часто при разработке на платформе 1С:Предприятие 7.7 программисты сталкиваются с парадоксальным поведением системы: визуально абсолютно одинаковые элементы не проходят стандартную проверку на равенство. Рассмотрим подробнее типичную ситуацию, когда в процедуре записи документа мы пытаемся сравнить две переменные, содержащие элементы одного и того же справочника.
Посмотрим на пример классического проблемного участка кода:
Процедура ПриЗаписи()
Если Фирма1 <> Фирма Тогда
СтатусВозврата(0);
Возврат;
КонецЕсли;
КонецПроцедуры
При отладке этого кода мы видим удивительную картину: переменные Фирма1 и Фирма ссылаются на один и тот же элемент справочника. Их наименование, код и внутренний системный идентификатор полностью совпадают, дублей в базе данных не существует. Однако система упорно выдает результат, что они не равны друг другу. Выясним причину такого поведения и разберем по шагам, как правильно сравнивать значения в 1С 7.7.
В основе архитектуры платформы 1С версии 7.7 лежит строгая разница между агрегатным объектом данных и статической ссылкой. Чтобы понять, почему возникает логическая ошибка при сравнении, разберем эти два понятия детально.
СоздатьОбъект или передается как текущий контекст самого модуля (формы). Он обладает встроенными методами: с его помощью мы можем искать новые записи, перебирать их в цикле, изменять значения конкретных реквизитов и физически сохранять их в базу данных.Когда мы оцениваем переменные в отладчике, платформа для нашего удобства выводит их строковое представление (чаще всего это значение реквизита "Наименование"). Поэтому визуально обе переменные кажутся нам совершенно идентичными. Но для встроенных операторов сравнения (таких как = или <>) они относятся к принципиально разным внутренним типам платформы. Из-за несовпадения базовых типов (динамический объект против статической ссылки) система корректно с технической точки зрения возвращает результат, что они не равны.
Чаще всего эта архитектурная особенность проявляется в предопределенной процедуре ПриЗаписи. Разберем механику возникновения конфликта. Реквизиты, которые расположены непосредственно на форме документа и выбираются пользователем в графическом интерфейсе, всегда имеют тип Ссылка. В то же время, данные, которые мы программно вычисляем, вытягиваем из текущего контекста или ищем в базе по коду, часто выступают в роли спозиционированных Объектов. Именно в момент логической проверки измененного пользователем значения с программно вычисленным и происходит невидимое столкновение типов.
Для корректного и надежного сравнения нам необходимо явно привести обе переменные к одному общему знаменателю, а именно — к ссылочному типу. Специально для этих целей в системе предусмотрен метод ТекущийЭлемент(). Этот метод быстро возвращает точное ссылочное значение того элемента справочника, на который в данный момент позиционируется наш программный объект.
Важная особенность этого метода заключается в его безопасности: если мы применим метод к переменной, которая уже является ссылкой, система не выдаст критическую ошибку, а просто вернет саму эту ссылку без изменений.
Рассмотрим правильный и универсальный вариант кода:
Если Фирма1.ТекущийЭлемент() <> Фирма.ТекущийЭлемент() Тогда
СтатусВозврата(0);
Возврат;
КонецЕсли;
Подобная логика сравнения распространяется не только на элементы справочников. Аналогичная проблема "неравенства самому себе" регулярно возникает при работе с другими важными типами данных. Для них в платформе предусмотрены аналогичные функции приведения типов:
ТекущийДокумент().ТекущийСчет().Разберем еще несколько критически важных аспектов, о которых необходимо помнить при проектировании алгоритмов сравнения.
Осторожность с позиционированием и пустыми значениями: Если объект был создан в памяти, но процедура поиска элемента не увенчалась успехом, метод ТекущийЭлемент() вернет пустую ссылку. Чтобы избежать скрытых логических ошибок, перед прямым сравнением мы рекомендуем проверять, спозиционирован ли объект на конкретной записи. Посмотрим на пример безопасного кода:
Если (Фирма1.Выбран() = 1) И (Фирма.Выбран() = 1) Тогда
Если Фирма1.ТекущийЭлемент() <> Фирма.ТекущийЭлемент() Тогда
Сообщить("Выбраны разные фирмы!");
КонецЕсли;
КонецЕсли;
Абсолютное строковое сравнение: Существует еще один альтернативный способ доказать платформе, что выбранные элементы полностью совпадают. Мы можем извлечь их внутренние системные идентификаторы (ID) базы данных и сравнить их как обычные строки. Для этого применяется функция преобразования ЗначениеВСтрокуВнутр():
Если ЗначениеВСтрокуВнутр(Фирма1) <> ЗначениеВСтрокуВнутр(Фирма) Тогда
СтатусВозврата(0);
Возврат;
КонецЕсли;
Данный метод конвертирует любые внутренние ссылки в уникальный текстовый формат (включающий внутренний ID объекта, таблицы и информационной базы). Однако на практике использование методов позиционирования типа ТекущийЭлемент() считается более профессиональным и правильным подходом, который обрабатывается движком 1С быстрее и формирует более читабельный код.