Что происходит внутри 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