Как проверить, содержит ли объект или форма экспортный метод в 1С

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

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

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

Проблема стандартного подхода через «Попытка — Исключение»

Первое решение, которое приходит в голову — это использование стандартной конструкции Попытка...Исключение. Мы можем просто попытаться вызвать метод напрямую:


Попытка
    Объект.ИмяЭкспортногоМетода();
Исключение
    // Метод не существует или произошла ошибка
КонецПопытки;

Проанализируем, почему этот способ является плохим и небезопасным в реальной разработке:

  1. Нежелательное выполнение кода (побочные эффекты): Если метод существует, он выполнится. Если этот метод выполняет запись данных, проведение документов, отправку писем или другие тяжелые операции, обычная «проверка» приведет к незапланированным действиям в базе данных.
  2. Маскирование реальных ошибок: Если метод существует, начал выполняться, но внутри него (например, на десятой строке кода) произошла системная ошибка (деление на ноль, обращение к несуществующему реквизиту), она будет перехвачена блоком Исключение. Программа посчитает, что метода просто нет, хотя он есть, но работает некорректно. Нам же нужно показать реальную ошибку выполнения пользователю или администратору.

Выясним, как обойти эти ограничения и выполнить «чистую» проверку наличия метода без его запуска.

Решение: Трюк с избыточными параметрами («Трюк с запятыми»)

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

Давайте рассмотрим универсальную функцию, реализующую этот подход:


Функция МетодРеализован(Объект, Знач ИмяМетода) Экспорт
    
    Если Объект = Неопределено Тогда
        Возврат Ложь;
    КонецЕсли;
    
    // Формируем вызов метода с заведомо избыточным количеством параметров (более 80 запятых)
    Запятые = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,";
    Выражение = "Объект." + ИмяМетода + "(" + Запятые + ")";
    
    ОписаниеОшибки = "";
    Попытка
        Выполнить(Выражение);
    Исключение
        ИнформацияОШибке = ИнформацияОбОшибке();
        ОписаниеОшибки = ИнформацияОШибке.Описание;
    КонецПопытки;
    
    // Анализируем полученную системную ошибку
    Если Найти(ОписаниеОшибки, "Метод объекта не обнаружен") > 0 
        Или Найти(ОписаниеОшибки, "Значение не является значением объектного типа") > 0 Тогда
        // Метода гарантированно нет у данного объекта
        Возврат Ложь;
    КонецЕсли;
    
    // Если ошибка связана с количеством параметров или типом вызова — метод существует!
    Если Найти(ОписаниеОшибки, "Слишком много фактических параметров") > 0 
        Или Найти(ОписаниеОшибки, "Обращение к процедуре объекта как к функции") > 0 Тогда
        Возврат Истина;
    КонецЕсли;
    
    // На случай англоязычной локализации платформы (клиентских лицензий или серверов)
    Если Найти(НРег(ОписаниеОшибки), "too many actual parameters") > 0 
        Или Найти(НРег(ОписаниеОшибки), "method not found") > 0 Тогда
        Возврат Найти(НРег(ОписаниеОшибки), "too many actual parameters") > 0;
    КонецЕсли;
    
    Возврат Ложь;
    
КонецФункции

Как это работает изнутри?

Разберем по шагам логику работы функции МетодРеализован():

  1. Строится строка динамического кода вида: "Объект.ИмяМетода(,,,,,,,,,,,,,,,,,,,)".
  2. Интерпретатор платформы пытается выполнить эту строку с помощью встроенного оператора Выполнить().
  3. Если метода с именем ИмяМетода у объекта нет, платформа генерирует исключение «Метод объекта не обнаружен» (или аналогичное англоязычное). Наша функция перехватывает его и возвращает Ложь.
  4. Если метод существует (даже если у него вовсе нет параметров или их всего 1-2), платформа видит несовпадение количества параметров в вызове и сигнатуре метода. Происходит системный сбой разбора выражения с ошибкой «Слишком много фактических параметров». Так как проверка параметров происходит до физического старта выполнения инструкций внутри метода, сам метод не запускается, данные не изменяются, но мы точно узнаем, что метод у объекта существует (функция возвращает Истина).

Альтернативные архитектурные варианты

Несмотря на то, что «трюк с запятыми» работает надежно и проверен годами практики, в крупных тиражных решениях (например, в конфигурациях на базе 1С:БСП) разработчики стараются избегать динамического выполнения кода через Выполнить() из-за требований безопасности и производительности. Рассмотрим альтернативные варианты архитектуры.

1. Использование свойств формы вместо методов

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


Если ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(Форма, "ПараметрОсобойОбработки") Тогда
    // Форма поддерживает нужный нам сценарий
КонецЕсли;

Этот способ работает быстрее, не использует компиляцию «на лету» и является абсолютно безопасным.

2. Явная регистрация интерфейсов (Подход БСП)

В Библиотеке стандартных подсистем часто применяется паттерн «Регистрация». Вместо того чтобы динамически искать экспортные функции у всех форм подряд, формы сами объявляют о своих возможностях при создании или инициализации. Например, через заполнение определенной структуры настроек или переопределение стандартных методов БСП (таких как ПриОпределенииНастроек).

Резюме

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

← На главную