Содержание
Что происходит внутри 1С, когда мы пишем спр.ТекущийЭлемент()?
1С преобразует имя метода ТекущийЭлемент в соответствующий ему номер, и вызывает метод объекта по номеру. НО, клинические исследования показали, что для ЛЮБОГО объекта 1С используется один алгоритм такого преобразования, реализованный "В ЛОБ", и котрый заключатся в простом последовательном переборе всех имен методов объекта и сравнении их с искомым. Соответственно, чем больше номер метода, тем большее время занимает такой поиск. Например, для того же "ТекущийЭлемент" перед реальным вызовом функции происходит перебор 88 названий методов.
Аналогично и для свойств объектов.
Как известно, для поиска номера метода применяется
virtual int CBLContext::FindMethod(const char* name);
Как оказалось, НИ В ОДНОМ из объектов 1С данный метод не переопределен. Перехват вызова функций различных объектов показал лень и мягко говоря, не вполне компетентность людей, писавших этот код.
Вобщем, когда вызывается FindMethod, из него вызываются: GetNMethods(), GetMethodName(i,0), GetMethodName(i,1) т.е. FindMethod работает примерно так:
for(int i=0;i<GetNMethods();i++) { if(!stricmp(name,GetMethodName(i,0)) return i; if(!stricmp(name,GetMethodName(i,1)) return i; } return -1;
Понятно, хотелось добиться универсальности и простоты, что и достигнуто. Но при этом: - Некомпетентность: GetNMethods можно вынести из цикла. - Лень: не зря же FindMethod виртуальная, почему же она не переопределена ни в одном из наследуемых классов для более оптимального поиска?
Аналогичная ситуация и с FindProp.
Дабы устранить досадную оплошность разработчиков 1С в отношении поиска методов и свойств была создана ВК TurboBL, которая включена в 1С++. Суть ее работы в следующем: оптимизация алгоритма преобразования имен методов/свойств в их номера.
Попутно сделана возможность обращаться к методам и переменным модулей ГрупповыхКонтекстов.
ЗагрузитьВнешнююКомпоненту("1cpp.dll");
Вот практически и все.
Более никаких изменений в существующем коде конфигурации не требуется. При загрузке компонента берет на себя всю работу по поиску номеров методов и свойств объектов 1С.
Да!!! Свершилось!!!
Теперь можно через контекст обратится к методам и переменным модуля контекста.
Например:
конт=0; ОткрытьФорму("Справочник.Товары",конт); конт.Печать(); //где Печать() - процедура в модуле ФормыСписка справочника. или например: // в модуле проведения дока Процедура ЭтоДокСТоваром() возврат 1; КонецПроцедуры; Процедура ОбработкаПроведения(парам) глНекаяГлобФункция(Контекст); .... // В ГМ: Процедура глНекаяГлобФункция(Конт) Если Конт.ЭтоДокСТоваром()=1 .......
Синтаксис: __ВызыватьМетодыКакСобытия(<Флаг>)
Параметр: Флаг - необязательный параметр. Число: 0 - отключает, 1 - включает вызов методов как событий.
Возвращает: Предыдущее установленное значение.
Описание: Вызов методов как событий влияет на установку номера строки для таблиц, расположенных на форме контекста, а также на подключение таблиц-шаблонов для объектов типа "Таблица", используемых в этом контексте (метод Таблица.ИсходнаяТаблица()).
Вызов метода влияет только на тот контекст, для которого он вызван. До вызова этого метода соответствующий ему флаг установлен в <1>.
Вызов метода (процедуры или функции) контекста может иметь разный результат в зависимости от того, был ли этот метод вызван из другого метода контекста, либо этот же метод вызван извне, например, по нажатию кнопки на форме. Например, для метода СообщитьНомерСтроки():
Процедура СообщитьНомерСтроки() Сообщить(тзНаФорме.НомерСтроки()); КонецПроцедуры Процедура СменитьИСообщить() тзНаФорме.ПолучитьСтрокуПоНомеру(1); СообщитьНомерСтроки(); КонецПроцедуры
Вызов же того же метода контекста извне может иметь даже более непредсказуемый результат:
Процедура СменитьИСообщитьДляКонтекста(Конт) Конт.тзНаФорме.ТекущаяСтрока(2); Конт.тзНаФорме.ПолучитьСтрокуПоНомеру(1); Конт.СообщитьНомерСтроки(); КонецПроцедуры
В результате вызова данной процедуры может вывестись как 1, так и 2. В зависимости от версии TurboBL (или 1С++), которую вы используете.
Для устранения данной неоднозначности и был добавлен метод групповых контекстов __ВызыватьМетодыКакСобытия(). Результатом вызова
Конт.__ВызыватьМетодыКакСобытия(0); СменитьИСообщитьДляКонтекста(Конт); Конт.__ВызыватьМетодыКакСобытия(1); СменитьИСообщитьДляКонтекста(Конт);
будет
1 2
Синтаксис: | __ДобавитьКонтекст(Конт) |
---|---|
Параметры: |
|
Возвращает: | Нет |
Описание: | Добавляет свойства и методы контекста к групповому контексту.
Данные методы и свойства становятся доступными в этом групповом контексте.
Конфликты имен разрешаются в пользу свойства или метода с меньшим порядковым номером.
Свойства можно только добавить, удалить нельзя.
Необходимо помнить, что добавление свойства к исходному контексту уже после добавления этого контекста к контексту формы
не добавит данное свойство к контексту формы, см. ОшибкаДобавленияСвойств !
Если необходимо добавлять/удалять свойства динамически, проще всего добавить какую-нибудь коллекцию в качестве свойства, см. ДобавлениеДинамическихСвойств .
Время жизни добавленного контекста привязано ко времени жизни формы.
|
Примеры использования: | |
Добавление простого свойства к контексту формы
Структура = СоздатьОбъект("Структура"); Структура.Вставить("ДопСвойство", "ПростоСтрока"); КонтФормы.__ДобавитьКонтекст(Структура); Сообщить("Новое свойство = "+КонтФормы.ДопСвойство);
результат выполнения
Новое свойство = ПростоСтрока
Добавление свойства к исходному контексту уже после его добавления к контексту формы - Это пример ошибки
для правильного использования см. ДобавлениеДинамическихСвойств
Структура = СоздатьОбъект("Структура"); Структура.Вставить("ДопСвойство", "ПростоСтрока"); КонтФормы.__ДобавитьКонтекст(Структура); Структура.Вставить("ДопСвойство2", "ПростоСтрока"); Сообщить("Новое свойство = "+КонтФормы.ДопСвойство); Сообщить("Новое свойство = "+КонтФормы.ДопСвойство2);
результат выполнения
Новое свойство = ПростоСтрока Ошибка: Поле агрегатного объекта не обнаружено - КонтФормы.ДопСвойство2
Работа с динамическими свойствами контекста
Структура = СоздатьОбъект("Структура"); Коллекция = СоздатьОбъект("АссоциативныйВектор"); Структура.Вставить("ДопСвойство", Коллекция); КонтФормы.__ДобавитьКонтекст(Структура); КонтФормы.ДопСвойство.Добавить(1, "Один"); Коллекция.Добавить(2, "Два"); // можно и так юзать, т.к. Коллекция = КонтФормы.ДопСвойство Сообщить("Количество = "+КонтФормы.ДопСвойство.Количество()); КонтФормы.ДопСвойство.Удалить("Два"); Сообщить("Количество = "+Коллекция.Количество());
результат выполнения
Количество = 2 Количество = 1