TurboBL

Содержание

Назначение

Краткий экскурс в механизм вызова методов

Для всех

Что происходит внутри 1С, когда мы пишем спр.ТекущийЭлемент()?

1С преобразует имя метода ТекущийЭлемент в соответствующий ему номер, и вызывает метод объекта по номеру. НО, клинические исследования показали, что для ЛЮБОГО объекта 1С используется один алгоритм такого преобразования, реализованный "В ЛОБ", и котрый заключатся в простом последовательном переборе всех имен методов объекта и сравнении их с искомым. Соответственно, чем больше номер метода, тем большее время занимает такой поиск. Например, для того же "ТекущийЭлемент" перед реальным вызовом функции происходит перебор 88 названий методов.

Аналогично и для свойств объектов.

Для знакомых с "Rainbow"

Как известно, для поиска номера метода применяется

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
    .......

Дополнительные методы групповых контекстов

__ВызыватьМетодыКакСобытия / __CallMethodsAsEvents

Синтаксис:

__ВызыватьМетодыКакСобытия(<Флаг>)

Параметр:

Флаг - необязательный параметр. Число: 0 - отключает, 1 - включает вызов методов как событий.

Возвращает:

Предыдущее установленное значение.

Описание:

Вызов методов как событий влияет на установку номера строки для таблиц, расположенных на форме контекста, а также на подключение таблиц-шаблонов для объектов типа "Таблица", используемых в этом контексте (метод Таблица.ИсходнаяТаблица()).

Вызов метода влияет только на тот контекст, для которого он вызван. До вызова этого метода соответствующий ему флаг установлен в <1>.

Вызов метода (процедуры или функции) контекста может иметь разный результат в зависимости от того, был ли этот метод вызван из другого метода контекста, либо этот же метод вызван извне, например, по нажатию кнопки на форме. Например, для метода СообщитьНомерСтроки():

Процедура СообщитьНомерСтроки()
        Сообщить(тзНаФорме.НомерСтроки());
КонецПроцедуры

Процедура СменитьИСообщить()
        тзНаФорме.ПолучитьСтрокуПоНомеру(1);
        СообщитьНомерСтроки();
КонецПроцедуры

Вызов же того же метода контекста извне может иметь даже более непредсказуемый результат:

Процедура СменитьИСообщитьДляКонтекста(Конт)
        Конт.тзНаФорме.ТекущаяСтрока(2);
        Конт.тзНаФорме.ПолучитьСтрокуПоНомеру(1);
        Конт.СообщитьНомерСтроки();
КонецПроцедуры

В результате вызова данной процедуры может вывестись как 1, так и 2. В зависимости от версии TurboBL (или 1С++), которую вы используете.

Для устранения данной неоднозначности и был добавлен метод групповых контекстов __ВызыватьМетодыКакСобытия(). Результатом вызова

Конт.__ВызыватьМетодыКакСобытия(0);
СменитьИСообщитьДляКонтекста(Конт);
Конт.__ВызыватьМетодыКакСобытия(1);
СменитьИСообщитьДляКонтекста(Конт);

будет

1
2

__ДобавитьКонтекст / __AddContext

Синтаксис:

__ДобавитьКонтекст(Конт)

Параметры:
  • Конт, тип: Контекст

    Контекст, который необходимо добавить к групповому контексту, для которого вызван метод

Возвращает:

Нет

Описание:
Добавляет свойства и методы контекста к групповому контексту.
Данные методы и свойства становятся доступными в этом групповом контексте.
Конфликты имен разрешаются в пользу свойства или метода с меньшим порядковым номером.
Свойства можно только добавить, удалить нельзя.
Необходимо помнить, что добавление свойства к исходному контексту уже после добавления этого контекста к контексту формы
не добавит данное свойство к контексту формы, см. ОшибкаДобавленияСвойств !
Если необходимо добавлять/удалять свойства динамически, проще всего добавить какую-нибудь коллекцию в качестве свойства, см. ДобавлениеДинамическихСвойств .

Время жизни добавленного контекста привязано ко времени жизни формы.
Примеры использования:
 

Добавление простого свойства к контексту формы

Структура = СоздатьОбъект("Структура");
Структура.Вставить("ДопСвойство", "ПростоСтрока");

КонтФормы.__ДобавитьКонтекст(Структура);

Сообщить("Новое свойство = "+КонтФормы.ДопСвойство);

результат выполнения

Новое свойство = ПростоСтрока

Добавление свойства к исходному контексту уже после его добавления к контексту формы - Это пример ошибки

для правильного использования см. ДобавлениеДинамическихСвойств

Структура = СоздатьОбъект("Структура");
Структура.Вставить("ДопСвойство", "ПростоСтрока");

КонтФормы.__ДобавитьКонтекст(Структура);

Структура.Вставить("ДопСвойство2", "ПростоСтрока");

Сообщить("Новое свойство = "+КонтФормы.ДопСвойство);
Сообщить("Новое свойство = "+КонтФормы.ДопСвойство2);

результат выполнения

Новое свойство = ПростоСтрока
Ошибка: Поле агрегатного объекта не обнаружено - КонтФормы.ДопСвойство2

Работа с динамическими свойствами контекста

Структура = СоздатьОбъект("Структура");
Коллекция = СоздатьОбъект("АссоциативныйВектор");
Структура.Вставить("ДопСвойство", Коллекция);

КонтФормы.__ДобавитьКонтекст(Структура);

КонтФормы.ДопСвойство.Добавить(1, "Один");
Коллекция.Добавить(2, "Два"); // можно и так юзать, т.к. Коллекция = КонтФормы.ДопСвойство
Сообщить("Количество = "+КонтФормы.ДопСвойство.Количество());
КонтФормы.ДопСвойство.Удалить("Два");
Сообщить("Количество = "+Коллекция.Количество());

результат выполнения

Количество = 2
Количество = 1