При разработке универсальных инструментов программисты 1С часто сталкиваются с проблемой: внешняя обработка, написанная для одной конфигурации, отказывается даже открываться в другой. Причина кроется в механизме работы платформы. Перед запуском или открытием формы система выполняет полный синтаксический контроль модуля. Если в коде встречается прямое обращение к общему модулю, глобальной переменной или объекту метаданных, который отсутствует в текущей конфигурации, платформа выдает ошибку "Переменная не определена" или "Объект не найден", и выполнение прерывается.
Рассмотрим подробнее, как обойти эти ограничения и заставить код работать в разных средах, используя приемы динамического программирования и особенности компиляции модулей 1С.
Важно понимать, что для платформы 1С не имеет значения, будет ли фактически исполнена строка кода с ошибкой. На этапе загрузки модуля происходит его компиляция. Проанализируем ситуацию: если вы написали ОбщегоНазначения.ЗаполнитьШапкуДокумента(), а модуля ОбщегоНазначения в базе нет, компилятор не сможет создать исполняемый код и заблокирует работу всей обработки. Наша задача — "спрятать" такие вызовы от компилятора и подсунуть их системе только в момент исполнения, когда мы уже точно знаем, что находимся в нужной конфигурации.
Это самый простой и распространенный способ обхода синтаксической проверки. Платформа воспринимает текст внутри этих функций как обычную строку и не проверяет её содержимое на этапе компиляции модуля.
Разберем пример. Вместо прямого обращения к глобальной переменной, которая может отсутствовать, мы используем функцию Вычислить():
// Вместо этого (вызовет ошибку компиляции):
// Пользователь = глТекущийПользователь;
// Используем это:
Попытка
Пользователь = Вычислить("глТекущийПользователь");
Исключение
Пользователь = ПараметрыСеанса.ТекущийПользователь; // Альтернатива для новых конфигураций
КонецПопытки;
Аналогично можно вызывать процедуры через Выполнить(). Посмотрим на пример вызова метода общего модуля:
ТекстКода = "ОбщегоНазначения.ЗаполнитьШапкуДокумента(ДокументОбъект, глТекущийПользователь)";
Попытка
Выполнить(ТекстКода);
Исключение
ЗаписьЖурналаРегистрации("Ошибка универсальной обработки", УровеньЖурналаРегистрации.Предупреждение,,, ОписаниеОшибки());
КонецПопытки;
Если в коде требуется часто обращаться к методам модуля, которого может не существовать, постоянно писать Выполнить() неудобно. Проанализируем более элегантный способ — получение ссылки на модуль в переменную.
// Определим переменную для модуля
М_ОбщегоНазначения = Неопределено;
// Попробуем инициализировать её
Попытка
М_ОбщегоНазначения = Вычислить("ОбщегоНазначения");
Исключение
// Модуль не найден, переменная останется Неопределено
КонецПопытки;
// Теперь вызываем методы безопасно
Если М_ОбщегоНазначения <> Неопределено Тогда
М_ОбщегоНазначения.ЗаполнитьШапкуДокумента(Параметры);
КонецЕсли;
Этот подход позволяет сохранить читаемость кода и избежать многократного использования строковых конструкций.
Чтобы код был действительно надежным, перед использованием Вычислить() или Выполнить(), рекомендуется программно проверить наличие объекта в метаданных. Это позволит избежать лишних исключений (Try-Catch), которые замедляют работу системы.
Выясним, как проверить существование общего модуля:
Функция ОбщийМодульСуществует(ИмяМодуля)
Возврат Метаданные.ОбщиеМодули.Найти(ИмяМодуля) <> Неопределено;
КонецФункции
// Пример использования
Если ОбщийМодульСуществует("ОбщегоНазначения") Тогда
Модуль = Вычислить("ОбщегоНазначения");
Модуль.НужнаяПроцедура();
КонецЕсли;
Такой же подход применим к документам, справочникам и параметрам сеанса. Например, проверка наличия параметра сеанса ТекущийПользователь:
Если Метаданные.ПараметрыСеанса.Найти("ТекущийПользователь") <> Неопределено Тогда
Значение = ПараметрыСеанса.ТекущийПользователь;
КонецЕсли;
Интересной особенностью платформы 1С является то, что модуль формы компилируется только в момент её открытия. Мы можем использовать это для создания конфигурационно-зависимых интерфейсов.
Рассмотрим алгоритм реализации:
Форма_УПП и Форма_ERP.ПриОткрытии (или ПриСозданииНаСервере для управляемых форм) определяем тип конфигурации и открываем нужную форму.В этом случае, если мы запустим обработку в "1С:ERP", форма для "1С:УПП" не будет загружена, и синтаксические ошибки в её модуле не помешают работе системы.
Если логика очень сложная и её невозможно просто обернуть в Выполнить(), можно вынести специфические блоки кода в текстовые макеты. Проанализируем эту ситуацию: вы создаете текстовый макет с именем Логика_БП, где пишете чистый код 1С. В основном модуле вы считываете этот текст и исполняете его.
ТекстСкрипта = ЭтотОбъект.ПолучитьМакет("Логика_БП").ПолучитьТекст();
Попытка
Выполнить(ТекстСкрипта);
Исключение
Сообщить("Не удалось выполнить специфическую логику: " + ОписаниеОшибки());
КонецПопытки;
Для создания качественного продукта придерживайтесь следующих правил:
ОбщегоНазначения.ЕстьСвойствоОбъекта().Попытка...Исключение и записывайте подробности ошибок, чтобы оперативно понять, почему в конкретной базе "что-то пошло не так".Таким образом, комбинируя методы динамического исполнения кода и проверки метаданных, мы можем создавать по-настоящему гибкие инструменты, которые значительно упрощают поддержку парка различных конфигураций 1С.