В процессе разработки на платформе «1С:Предприятие 8» программисты часто сталкиваются с необходимостью создания универсальных механизмов. Одной из таких задач является определение того, какому именно объекту (справочнику, документу или регистру) принадлежит текущий модуль менеджера. Трудность заключается в том, что в модуле менеджера, в отличие от модуля объекта, отсутствует контекстное ключевое слово ЭтотОбъект. Следовательно, мы не можем напрямую обратиться к свойствам метаданных через простую ссылку.
В этой статье мы подробно разберем, какими способами можно «самоидентифицироваться» внутри модуля менеджера, проанализируем различные типы данных и выберем наиболее эффективные методы для решения этой задачи.
Рассмотрим ситуацию: у нас есть общий модуль, который выполняет сложную обработку данных, и мы хотим вызывать его функции из модулей менеджера разных справочников. Чтобы не прописывать имя метаданных вручную в каждом вызове (что чревато ошибками при копировании кода), мы хотим, чтобы код сам определял: «Я нахожусь в менеджере Справочника Номенклатура» или «Я нахожусь в менеджере Документа РеализацияТоваровУслуг».
Для всех объектов, которые имеют ссылочную природу, платформа предоставляет метод ПустаяСсылка(). Это самый быстрый и надежный способ получить тип объекта, а затем найти его в дереве метаданных. Разберем этот алгоритм по шагам.
Воспользуемся встроенной функцией ТипЗнч() для получения типа пустой ссылки, а затем методом глобального контекста Метаданные.НайтиПоТипу() для получения объекта описания метаданных.
Пример кода для модуля менеджера справочника или документа:
// Определяем тип объекта через пустую ссылку
ТипОбъекта = ТипЗнч(ПустаяСсылка());
// Получаем объект метаданных по типу
ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипОбъекта);
// Получаем полное имя (например, "Справочник.Номенклатура")
ПолноеИмя = ОбъектМетаданных.ПолноеИмя();
Этот метод считается эталонным для ссылочных типов, так как он не создает лишних объектов в памяти и работает максимально быстро.
С регистрами сведений ситуация несколько сложнее, так как у них нет понятия «ссылки», а значит, метод ПустаяСсылка() в их модуле менеджера отсутствует. Однако у регистров сведений есть метод СоздатьКлючЗаписи(). Если вызвать его без параметров, он вернет пустой ключ записи определенного типа.
Проанализируем пример получения метаданных для регистра сведений:
// Создаем пустой ключ записи и получаем его тип
ТипКлюча = ТипЗнч(СоздатьКлючЗаписи());
// Находим метаданные по типу ключа
ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипКлюча);
// Выводим результат
Сообщить(ОбъектМетаданных.ПолноеИмя());
Важно помнить, что этот метод специфичен именно для регистров сведений. Для регистров накопления или расчета он не подойдет, так как структура их ключей и способы обращения в менеджере отличаются.
В модулях менеджера отчетов и обработок мы можем воспользоваться методом Создать(). Этот метод создает экземпляр объекта, у которого уже есть доступ к свойству Метаданные().
Рассмотрим реализацию:
// Создаем экземпляр обработки/отчета
ОбъектЭкземпляр = Создать();
// Получаем полное имя из метаданных объекта
ИмяОбъекта = ОбъектЭкземпляр.Метаданные().ПолноеИмя();
Внимание: Использование метода Создать() внутри модуля менеджера может привести к избыточному потреблению ресурсов, если это происходит внутри часто вызываемых процедур или циклов, так как создание объекта — операция сравнительно «дорогая».
Если нам нужно решение, которое будет работать вообще в любом модуле менеджера (включая регистры накопления, где нет пустых ссылок или простых ключей), мы можем прибегнуть к анализу стека вызовов. Это более сложный, но универсальный «хакерский» метод.
Выясним причину, почему это работает: при возникновении исключения платформа фиксирует путь к коду, где произошла ошибка. Мы можем программно вызвать ошибку, перехватить ее и распарсить строку стека.
Посмотрим на пример реализации для современных версий платформы (8.3.10+):
Попытка
// Генерируем исключение
ВызватьИсключение "ОпределяемКонтекст";
Исключение
Информация = ИнформацияОбОшибке();
// Анализируем стек вызовов
Для Каждого СтрокаСтека Из Информация.СтекВызовов Цикл
// Строка обычно содержит: "Справочник.Номенклатура.МодульМенеджера : 15 : ИмяПроцедуры"
Если Найти(СтрокаСтека.Представление, "МодульМенеджера") > 0 Тогда
// Здесь можно применить регулярные выражения или функции работы со строками
// для выделения части "Справочник.Номенклатура"
Прервать;
КонецЕсли;
КонецЦикла;
КонецПопытки;
Этот метод стоит использовать только в крайних случаях, когда другие способы недоступны, так как работа с исключениями замедляет выполнение кода.
Несмотря на наличие программных способов «узнать себя», в профессиональной разработке и стандартах (например, БСП — Библиотека стандартных подсистем) рекомендуется придерживаться следующих правил:
Метаданные.НайтиПоТипу(), результат определения стоит сохранить в повторно используемое значение или переменную модуля (если это допустимо контекстом), чтобы не нагружать сервер повторными поисками.Подведем итог: наиболее эффективным и правильным способом для большинства объектов является использование комбинации ТипЗнч(ПустаяСсылка()) и Метаданные.НайтиПоТипу(). Это решение обеспечивает отличную производительность и надежность кода.