При разработке в среде 1С:Предприятие 8.3 программисты часто сталкиваются с ошибкой «Метод объекта не обнаружен» при попытке вызвать процедуру или функцию общего модуля из расширения. Ситуация становится особенно запутанной, когда тот же самый код успешно работает во внешней обработке, но отказывается функционировать внутри расширения конфигурации. В этой статье мы подробно разберем, как устроены контексты выполнения, почему директивы компиляции в общих модулях работают не так, как в формах, и как правильно организовать архитектуру кода, чтобы избежать подобных проблем.
Основная причина проблемы кроется в фундаментальном непонимании того, как платформа 1С компилирует программный код. Когда мы говорим об общем модуле, его доступность определяется не только ключевым словом Экспорт, но и набором флажков (свойств) в палитре свойств модуля. Рассмотрим их подробнее:
Проанализируем ситуацию автора вопроса: в общем модуле снята галочка «Клиент», но внутри написана процедура с директивой &НаКлиенте. Это главная логическая ошибка. В общих модулях директивы &НаКлиенте и &НаСервере игнорируются платформой, если соответствующие флаги не проставлены в свойствах самого модуля. Если у модуля стоит только флаг «Сервер», то абсолютно все процедуры в нем будут считаться серверными, даже если перед ними написано &НаКлиенте.
Выясним причину разного поведения системы. Внешние обработки часто запускаются в режиме толстого клиента или имеют специфические допуски по обращению к метаданным. Расширения же работают по строгим правилам текущего контекста. Если вы находитесь в модуле формы расширения в клиентском методе (&НаКлиенте) и пытаетесь вызвать метод общего модуля, у которого не стоит флаг «Клиент», платформа просто не «видит» этот метод в клиентском окружении. Для клиентского приложения этого метода физически не существует в оперативной памяти.
Разберем еще один важный нюанс. Автор пытается вызвать окно сохранения файла из модуля, который настроен как серверный. На сервере не существует графического интерфейса. Выполнение кода на сервере происходит в изолированном процессе, который ничего не знает о мониторе, мыши или диалоговых окнах пользователя. Поэтому попытка вызвать ДиалогВыбораФайла или любое другое интерактивное окно из серверного контекста приведет к ошибке, даже если вы сможете «достучаться» до этой процедуры.
Проанализируем, как нужно изменить настройки, чтобы код заработал. Рассмотрим два основных сценария.
Если вы хотите оставить логику в одном модуле, выполните следующие действия:
Пример правильного оформления кода в таком модуле:
#Если Клиент Тогда
Процедура СохранитьФайлНаКлиенте() Экспорт
// Здесь код вызова диалога выбора файла
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
// ... логика работы с диалогом
КонецПроцедуры
#КонецЕсли
#Если Сервер Тогда
Процедура ОбработатьДанныеНаСервере() Экспорт
// Здесь код запроса к базе данных
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура");
// ... логика обработки
КонецПроцедуры
#КонецЕсли
Важно: При такой настройке клиентская часть расширения увидит процедуру СохранитьФайлНаКлиенте, а серверная — ОбработатьДанныеНаСервере. Однако помните, что установка обоих флагов заставляет систему компилировать две копии модуля, что может увеличить потребление памяти.
Лучшая практика разработки в 1С (согласно стандартам фирмы «1С») предполагает разделение ответственности. Рассмотрим этот подход подробнее:
РаботаСФайламиКлиент. Устанавливаем только флаг «Клиент (управляемое приложение)». В нем размещаем все интерактивные действия.РаботаСФайламиСервер. Устанавливаем флаг «Сервер» и «Вызов сервера». В нем размещаем расчеты и работу с базой данных.Теперь из модуля формы в расширении вы сможете вызывать их соответствующим образом:
&НаКлиенте
Процедура КомандаСохранить(Команда)
// Вызываем клиентский общий модуль для выбора пути
ПутьКФайлу = РаботаСФайламиКлиент.ПолучитьПутьДляСохранения();
Если ЗначениеЗаполнено(ПутьКФайлу) Тогда
// Вызываем серверный модуль для формирования данных
ДанныеФайла = РаботаСФайламиСервер.СформироватьДанныеДляВыгрузки();
ДанныеФайла.Записать(ПутьКФайлу);
КонецЕсли;
КонецПроцедуры
Выясним, почему расширения ведут себя более «капризно». Когда вы добавляете вызов общего модуля в расширение, платформа выполняет строгую проверку типов и контекстов на этапе компиляции расширения. Если общий модуль основной конфигурации не помечен как клиентский, расширение не позволит использовать его методы в клиентских процедурах расширения.
Если вам необходимо изменить поведение существующего общего модуля через расширение (использовать &Вместо, &Перед или &После), помните:
Подводя итог, проанализируем основные правила решения проблемы:
&НаКлиенте), у общего модуля обязательно должен стоять флаг «Клиент».&НаКлиенте / &НаСервере работают в модулях форм и команд. В общих модулях используйте инструкции препроцессора #Если Клиент Тогда ... #КонецЕсли.Соблюдение этих архитектурных принципов позволит вам создавать стабильные расширения, которые не будут выдавать неожиданных ошибок Метод объекта не обнаружен при попытке совершить простейшие действия.