Почему ЭтотОбъект.ДополнительныеСвойства возвращает неожиданный результат и как правильно использовать метод Свойство() в 1С?

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

При разработке в среде 1С:Предприятие программисты часто сталкиваются с необходимостью передачи временных параметров между различными процедурами и модулями одного объекта. Самым популярным и штатным инструментом для этого является свойство ДополнительныеСвойства, которое присутствует у большинства прикладных объектов (справочников, документов, процессов и т.д.) и представляет собой коллекцию типа Структура. Однако некорректное использование методов этой коллекции может приводить к трудноуловимым логическим ошибкам. Рассмотрим подробно одну из таких ситуаций, разберем причины ее возникновения и найдем оптимальные пути решения.

Анализ проблемы: почему метод Свойство() возвращает Истина?

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

Для этого в модуле объекта пишется следующий код:


Процедура ПередЗаписью(Отказ)
    Если Не Отказ Тогда
        ЭтоНовый_ЦентральнойБазы = ЭтоНовый() И Не ЭтоГруппа; 
        ЭтотОбъект.ДополнительныеСвойства.Вставить("ЭтоНовый_ЦентральнойБазы", ЭтоНовый_ЦентральнойБазы);
    КонецЕсли;
КонецПроцедуры

Затем в процедуре ПриЗаписи() разработчик пытается прочитать переданный флаг:


Процедура ПриЗаписи(Отказ)
    СтруктураДопСвойств = ЭтотОбъект.ДополнительныеСвойства;
    ЭтоНовый_ЦБ = СтруктураДопСвойств.Свойство("ЭтоНовый_ЦентральнойБазы");
    // Дальнейшая логика работы с флагом...
КонецПроцедуры

И вот здесь возникает странность: переменная ЭтоНовый_ЦБ всегда принимает значение Истина, вне зависимости от того, записывается новый элемент или перезаписывается старый. При этом прямое обращение через точку СтруктураДопСвойств.ЭтоНовый_ЦентральнойБазы возвращает корректное значение (Истина или Ложь), но только если свойство гарантированно существует.

Выясним причину такого поведения. Метод Свойство() объекта Структура в платформе 1С предназначен исключительно для проверки наличия ключа в этой структуре. Он возвращает булево значение:

Поскольку в обработчике ПередЗаписью() мы принудительно вставляем ключ "ЭтоНовый_ЦентральнойБазы" со значением Ложь (при перезаписи существующего элемента), метод Свойство() находит этот ключ и честно возвращает Истина (ключ существует!). Разработчик же ошибочно интерпретирует этот результат как значение самого флага.

Решение 1. Использование второго параметра метода Свойство() (Канонический способ)

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

Свойство(Ключ, НайденноеЗначение)

Если ключ найден в структуре, то платформа записывает его значение в переменную, переданную во втором параметре. Это позволяет избежать двойных проверок и защищает код от падения с ошибкой «Поле объекта не обнаружено».

Перепишем наш код в процедуре ПриЗаписи() правильным и максимально безопасным способом:


Процедура ПриЗаписи(Отказ)
    ЭтоНовый_ЦБ = Ложь; // Задаем дефолтное значение на случай, если ключа нет
    
    // Если ключ существует, его реальное значение запишется в переменную ЭтоНовый_ЦБ
    ЭтотОбъект.ДополнительныеСвойства.Свойство("ЭтоНовый_ЦентральнойБазы", ЭтоНовый_ЦБ);
    
    Если ЭтоНовый_ЦБ Тогда
        // Наша логика для нового элемента
    КонецЕсли;
КонецПроцедуры

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

Решение 2. Проверка наличия ключа и последующее обращение

Если по каким-то причинам использование второго параметра вам не подходит, можно воспользоваться классической схемой проверки «если свойство существует, берем его значение, иначе используем значение по умолчанию»:


Процедура ПриЗаписи(Отказ)
    СтруктураДопСвойств = ЭтотОбъект.ДополнительныеСвойства;
    
    Если СтруктураДопСвойств.Свойство("ЭтоНовый_ЦентральнойБазы") Тогда
        ЭтоНовый_ЦБ = СтруктураДопСвойств.ЭтоНовый_ЦентральнойБазы;
    Иначе
        ЭтоНовый_ЦБ = Ложь;
    КонецЕсли;
КонецПроцедуры

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

Важное предупреждение: Ни в коем случае не используйте конструкцию вида:

ЭтоНовый_ЦБ = СтруктураДопСвойств.Свойство("ЭтоНовый_ЦентральнойБазы") И СтруктураДопСвойств.ЭтоНовый_ЦентральнойБазы;

Хотя логически она кажется верной, она таит в себе скрытую угрозу. Если ключ "ЭтоНовый_ЦентральнойБазы" отсутствует в структуре, платформа 1С попытается вычислить все части логического выражения «И» и споткнется на второй части, выдав ошибку выполнения: «Поле объекта не обнаружено (ЭтоНовый_ЦентральнойБазы)». В 1С логические выражения вычисляются полностью, без оптимизации «короткого пути» (short-circuit evaluation).

Глубокое понимание работы ДополнительныеСвойства

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

  1. Существуют только в оперативной памяти. Данные, помещенные в ДополнительныеСвойства, никогда не записываются в базу данных. Это исключительно временное хранилище для обмена информацией в рамках сеанса работы с конкретным экземпляром объекта.
  2. Стираются при пересоздании объекта. Если в коде происходит перечитывание данных из БД (метод Прочитать()) или получение объекта заново (например, при конвертации на клиенте/сервере через РеквизитФормыВЗначение("Объект")), будет создан новый экземпляр объекта в оперативной памяти, а все ранее накопленные в нем ДополнительныеСвойства будут безвозвратно утеряны.
  3. Недоступны у Ссылок. Данное свойство присутствует только у тяжелых объектных типов данных (СправочникОбъект, ДокументОбъект и т. д.). Попытка обратиться к нему через ссылку (ЭтотОбъект.Ссылка.ДополнительныеСвойства) приведет к ошибке компиляции или выполнения.

Важное правило безопасности: Конфликты с БСП (Библиотекой Стандартных Подсистем)

Многие начинающие программисты совершают критическую ошибку, полностью инициализируя структуру заново в коде модуля объекта:

ЭтотОбъект.ДополнительныеСвойства = Новый Структура("МойПараметр", Значение); // ТАК ДЕЛАТЬ КАТЕГОРИЧЕСКИ НЕЛЬЗЯ!

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

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

Золотое правило работы с дополнительными свойствами: Всегда используйте только метод Вставить(), чтобы аккуратно добавлять свои параметры в существующую коллекцию, не затрагивая чужие данные:

ЭтотОбъект.ДополнительныеСвойства.Вставить("МойПараметр", Значение); // Правильный и безопасный подход

Архитектурное назначение: Подписки на события

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

Когда срабатывает подписка на событие (например, ПередЗаписьюДокумента), платформа передает в обработчик только сам объект (параметр Источник). У общего модуля, в котором выполняется подписка, нет прямого доступа к экранной форме или к реквизитам формы, инициировавшей запись.

Запись необходимых флагов в ЭтотОбъект.ДополнительныеСвойства в модуле формы перед вызовом метода Записать() — это единственный надежный и правильный способ «прокинуть» контекст (например, признак того, что запись выполнена интерактивно пользователем, или требование пропустить определенные проверки) в процедуры общих модулей подписок на события.

← На главную