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