Страница 1 из 1
использование bind в очереди
Добавлено: 09 Июнь 2006, 17:33
ru_alex
Всем привет!
Ситуация. Есть очередь, в ней как элемент еще одна, пользователь с помощью некоего интерфейса задает как эта очередь заполняется из файлов, вообщем получается некая формула. Можно складывать ряды, вычитать и т.д. Все это я пытаюсь реализовать оператором evaluate. Приходится биндить поля из очереди. Так вот, пришел к тому, что для каждой записи верхней очереди мне придется биндить отдельно элементы внутренней очереди, соответственно со стороны пользователя я не могу просто сформировать выражение и затем при расчете вызвать evaluate и все. Пока вижу решение в том, что выражение придется разбирать и формировать заново для каждой записи.
Можно ли это обойти проще и красивей?
Добавлено: 10 Июнь 2006, 0:57
Олег
Работать с очередью через блок Evaluate нельзя. По очень простой причине - разработчик не имеет возможность получить реальный адрес какой-либо записи очереди, а доступен только адрес буфера этой очереди, в котором в разные моменты времени могут быть данные из разных записей. Более того - даже если "вытащить" эти реальные адреса с помощью RTL, то в большинстве случае это не поможет из-за упаковки записей. Т.е., приходим к тому, что В ЛЮБОМ СЛУЧАЕ перед работой с данными очереди НЕОБХОДИМО из очереди вытащить нужную запись посредством стандартных операторов.
В качестве решения можно предложить следующий алгоритм:
- пишем функцию, например GetData, которая на вход принимает номер нужной записи и наименование поля. В качестве наименования можно использовать как реальные метки полей записи очереди, так и свои более осмысленные названия. Во втором случае, для доступа к полям можно или воспользоваться аттрибутом NAME в декларации очереди, или просто проBIND-овать нужные поля БУФЕРА очереди. Как, недеюсь, понятно - в самой функции идет чтение нужной записи из очереди и возврат значения запрошенного поля.
В принципе, это все!
BIND('ВзятьДанные',GetData)
Теперь выражение будет выглядеть таким образом:
ВзятьДанные(1,'Цена') * ВзятьДанные(2,'Количество')
Если полей, которые может использовать пользователь в выражениях, не очень много, то можно еще больше упростить ему работу - написать функции-обертки над GetData по именам этих полей:
Price PROCEDURE(LONG _QueRecNum)
Code
Return(GetData(_QueRecNum,'Цена'))
Total PROCEDURE(LONG _QueRecNum)
Code
Return(GetData(_QueRecNum,'Количество'))
BIND('Цена',Price)
BIND('Количество',Total)
Тогда вышеописанное выражение пользователь сможет описать так:
Цена(1) * Количество(2)
Или я неправильно понял проблему?
Добавлено: 13 Июнь 2006, 16:17
ru_alex
Именно то, что нужно, спасибо.
Есть ли возможность забиндить метод класса?
Как evaluate обрабатывает деление на ноль? Вроде возвращает ноль, это так предусмотрено?
Добавлено: 13 Июнь 2006, 20:09
Олег
ru_alex писал(а):Есть ли возможность забиндить метод класса?
Напрямую, увы, невозможно. Из-за того, что первым параметром в методе класса ВСЕГДА идет скрытый адрес класса типа LONG. Можно только через обычную процедуру-обертку.
ru_alex писал(а):Как evaluate обрабатывает деление на ноль? Вроде возвращает ноль, это так предусмотрено?
Evaluate-блок САМ НИЧЕГО НЕ ВЫЧИСЛЯЕТ! Для этого он вызвает те блоки RTL, которые и предназначены для обработки тех или иных типов данных. Т.е., другими словами, Evaluate-блок производит вычисления ПО ТЕМ-ЖЕ ПРАВИЛАМ, что и обычные вычисления, записанные прямо в коде программы.
Добавлено: 15 Июнь 2006, 9:15
ru_alex
Олег, спасибо.
Пока все идет на ура.