Возможно ли создать динамический объект

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Возможно ли создать динамический объект

Сообщение ger_kar » 16.11.2014 (Вс) 6:53

Возник вопрос, пока больше из чисто академических соображений, нежели из практической плоскости, так как на практике вполне себе можно обойтись и без этого. Речь вот о чем.
Возможно ли создать объект с переменным количеством членов - методов интерфейса и дополнив стандартную коллекцию такими возможностями получить следующее: При добавлении нового члена в коллекцию добавлять к интерфейсу оной дополнительно новый член напрямую связанный с элементом коллекции. И собственно вопросы. Возможно ли вообще это реализовать (на VB6 конечно)? Если да, то как примерно это сделать? И применяется ли такой подход на практике? Причем последний вопрос не ограничивается сферой только одного VB6. Если такая технология применяется, как она правильно называется? Я назвал динамический объект, но не уверен, что это правильно.
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16477
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Возможно ли создать динамический объект

Сообщение Хакер » 16.11.2014 (Вс) 9:07

ger_kar писал(а):Возможно ли создать объект с переменным количеством членов ... И собственно вопросы. Возможно ли вообще это реализовать

Да.

ger_kar писал(а):(на VB6 конечно)

В той или иной степени.

ger_kar писал(а): Если да, то как примерно это сделать?

Сделать свою собственную реализацию IDispatch.

ger_kar писал(а):И применяется ли такой подход на практике?

Естественно. В скриптах и/или языках и механизмах расширения.

ger_kar писал(а):Если такая технология применяется, как она правильно называется? Я назвал динамический объект

Называется позднее связывание по имени + динамическая диспетчеризация вызова. Вот только объект тут не причём, потому что что вообще такое объект никому не известно. А интерфейс называется дисп-интерфейсом.

tyomitch писал(а):Второй основой COM, после виртуальных методов, является интерфейс IDispatch, который позволяет работать с объектами, тип которых неизвестен заранее. Чтобы вызывать методы класса, реализующего этот интерфейс, достаточно знать их имена. Метод IDispatch::GetIDsOfNames возвращает по имени метода его DispID -- 4-байтный идентификатор, совпадающий по смыслу с идентификатором динамических методов в Delphi. DispID метода должен сохраняться неизменным на всём времени жизни объекта, возвратившего его по вызову GetIDsOfNames. Другой метод, IDispatch::Invoke, вызывает произвольный метод объекта по DispID. Аргументы для этого метода передаются в Invoke как массив типа Variant.

Единая точка входа для всех методов класса обеспечивает такую же гибкость, которая в прошлый раз описывалась применительно к "полувиртуальным" методам. Метод Invoke может содержать произвольную логику, управляющую соотнесением DispID и конкретной реализации метода: он может менять обработчик во время выполнения, может передавать вызов на обработку классу-предку в зависимости от каких-либо условий и т.д. Фактически, связывание методов dispatchable-классов полностью перенесено с компилятора на объекты этих классов.

Наследование dispatchable-классов осуществляется в лучших традициях "маршрутизации сообщений" в Smalltalk. В отличие от наследования обычных классов, внешний интерфейс полностью образуется классом-потомком: классы-предки в него не "вмонтируются", как в предыдущих случаях. Вместо этого объекты-предки "агрегируются" вглубь потомка, как это обычно при реализации "наследования" в VB6, и реализации методов IDispatch класса-потомка просто внутри себя вызывают методы предков для всех методов, которые в этом классе-потомке не переопределены. Таким образом, каждый вызов метода класса с большим деревом предков последовательно маршрутизируется по ветвям этого дерева, пока не дойдёт до нужного узла. Поскольку здесь при множественном наследовании не создаётся ни кучи виртуальных таблиц, ни кучи корректоров, как в предыдущих примерах -- IDispatch предоставляет идеальный механизм для множественого наследования. С определёнными ухищрениями типа замены стандартной реализации IDispatch на собственную, это множественное наследование становится доступным и для классов VB6.

Соответственным образом преображается применительно к dispatchable-классам понятие COM-интерфейса: для классов со связыванием по VTbl интерфейс (в понятиях C++ -- чисто абстрактный (pure abstract) базовый класс) -- это виртуальная таблица, которую класс должен обязательно включать. Например, любой COM-класс обязан поддерживать интерфейс IUnknown, т.е. у любого COM-класса должна быть виртуальная таблица, совпадающая с виртуальной таблицей IUnknown. Для dispatchable-классов вместо понятия "интерфейс" применяется "диспинтерфейс" (dispinterface): это набор DispID, которые должен поддерживать класс. У многих отрицательных DispID есть специальные значения: наиболее известный из них -- DISPID_NEWENUM = -4 -- соответствует методу, возвращающему перечислитель для класса-коллекции; менее известный DISPID_AMBIENT_MESSAGEREFLECT = -706 соответствует свойству, возвращающему True, если класс является ActiveX-контролом, поддерживающим отражение сообщений. Нулевой DispID соответствует "свойству по умолчанию".

Dispatchable-классы в COM удивительно схожи с оконными процедурами: точно так же, как все обработчики оконных сообщений для одного окна, все методы одного объекта имеют общую точку входа, которой передаётся числовой идентификатор вызываемого метода и набор универсальных параметров, конкретный смысл которых меняется от одного метода к другому. Как и для окон, для dispatchable-классов легко создать подкласс, перехватив вызов Invoke и в зависимости от переданных параметров либо возвращая управление исходному обработчику, либо осуществляя собственную обработку.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Возможно ли создать динамический объект

Сообщение ger_kar » 16.11.2014 (Вс) 11:48

Спасибо за развернутый ответ :)
Хакер писал(а):Называется позднее связывание по имени + динамическая диспетчеризация вызова. Вот только объект тут не причём, потому что что вообще такое объект никому не известно. А интерфейс называется дисп-интерфейсом.
Ну как же объект не причем. Тут вообще конечно я может и не совсем правильно выразился, но имелось ввиду, что есть некий объект хранилище (в моем случая хранящий ссылки на элементы коллекции) и реализующий некий динамически изменяющийся интерфейс. В любом случае интерфейс зависит от объекта. Т.е. как у дерева ствол и ветви. Объект это ствол имеющий ветви - интерфейсы (в моем представлении :) )
Но исходя из ответа получается, что интерфейс то по сути может и не быть динамическим? Т.е. Обычный статический IDispatch. Статический в том смысле, что олицетворяющая его VTable может оставаться в статичном состоянии, не приростая новыми методами. Все по сути будет происходить через сам IDispatch и его методы, а он сам, будет перенаправлять вызовы и при этом по барабану что они не будут выведены в VTable, так как IDispatch все равно будет знать где они находятся, а ранний вызов в любом случае невозможен. Так?

И при таком раскладе реализации на VB6, с наличием возможности делать вызов по указателю особой проблемы вызвать не должна. Хотя может даже и такой вызов не понадобится.
Бороться и искать, найти и перепрятать

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Возможно ли создать динамический объект

Сообщение The trick » 16.11.2014 (Вс) 12:05

Тебе просто нужно переопределить GetIDsOfNames и Invoke. Добавив свои DISPID'ы, в Invoke ты будешь перенаправлять вызовы в новые процедуры. Только непонятно зачем такое понадобилось.?
UA6527P

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Возможно ли создать динамический объект

Сообщение ger_kar » 16.11.2014 (Вс) 13:59

Практически пока не понадобилось, просто стало интересно.
А мысли такие навеяла 1С с её динамической структурой. С одной стороны она вроде как и коллекция, а с другой как как один объект с множеством свойств, по числу своих членов. В принципе это может быть сама обычная коллекция, а двойственность представления это всего лишь реализация самого встроенного языка. По сути на уровне языка в VB6 есть практически то же самое. Если брать например коллекцию VB6, то по сути можно опустив использование Item а также скобки и другие атрибуты, обращаться к элементам коллекции через восклицательный знак. Но также подумалось и другое, то, о чем я собственно и спросил :) . Бывает мысль, как вирус, как прицепится...
Кстати если сделать IDispatch для реализации того, о чем я спрашивал, то получится по сути практически тоже самое, что и метод Item, только доступ к элементам коллекции будет через GetIDsOfNames и Invoke, и скорее всего обычный доступ через Item будет даже более производительным. Да и использование точки на уровне языка по сути мало отличается от использования ! Но вдруг когда нибудь, зачем нибудь, да и понадобится...
Бороться и искать, найти и перепрятать

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 17.11.2014 (Пн) 13:08

Что-то я не уловил мысли про коллекцию по отношению к VB6 - в нём же коллекцию функций не сделаешь.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16477
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Возможно ли создать динамический объект

Сообщение Хакер » 17.11.2014 (Пн) 13:09

Вообще-то можно.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 17.11.2014 (Пн) 13:13

Тем же способом, как у тебя вызов по указателю сделан, или есть более стандартный?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16477
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Возможно ли создать динамический объект

Сообщение Хакер » 17.11.2014 (Пн) 13:21

Qwertiy писал(а):Тем же способом, как у тебя вызов по указателю сделан, или есть более стандартный?

Абсолютно не тем. Мы ведь говорим о трюках за счёт IDispatch, а этим в моём способе с указателями не пахнет.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 17.11.2014 (Пн) 13:38

Хакер писал(а):Мы ведь говорим о трюках за счёт IDispatch

Не, я не про него сейчас, а про это:
ger_kar писал(а):получится по сути практически тоже самое, что и метод Item, только доступ к элементам коллекции будет через GetIDsOfNames и Invoke, и скорее всего обычный доступ через Item будет даже более производительным. Да и использование точки на уровне языка по сути мало отличается от использования ! Но вдруг когда нибудь, зачем нибудь, да и понадобится...
Т. е. вместо реализации IDispatch как-то реализовать коллекцию и обращаться по принципу Smth!DoIt() - такое вроде стандартными средствами не выйдет?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16477
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Возможно ли создать динамический объект

Сообщение Хакер » 17.11.2014 (Пн) 13:40

Qwertiy писал(а):Т. е. вместо реализации IDispatch как-то реализовать коллекцию и обращаться по принципу Smth!DoIt() - такое вроде стандартными средствами не выйдет?

Во-первых, выйдет. Во-вторых, зачем «вместо»? (Хотя можно и вместо).
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 17.11.2014 (Пн) 13:43

Хакер писал(а):Во-первых, выдётет.

Каким образом? Поместить в коллекцию некий объект, имеющий дефаултное свойство?

Хакер писал(а):Во-вторых, зачем «вместо»? (Хотя можно и вместо).

А вот вместо или вместе - не важно, просто по контексту цитаты больше подходило :)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16477
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Возможно ли создать динамический объект

Сообщение Хакер » 17.11.2014 (Пн) 14:16

Qwertiy писал(а):Каким образом? Поместить в коллекцию некий объект, имеющий дефаултное свойство?

Объект, который олицетворяет процедуру, у которого будет метод (назовём его Invoke), у которого будут ParamArray-аргументы и который будет промаркирован как член-по-умолчанию. То есть не обязательно это должно быть get-свойство, это может быть и метод.

Вот например, делаю класс по имени Callable:
Код: Выделить всё
Public Function Invoke(ParamArray args() As Variant)
    Debug.Print "Something callable has been called with args: ";
    For Each arg In args
        Debug.Print arg;
    Next arg
    Debug.Print "."
    CallThis = Int(Rnd * 100)
End Function

В Procedure Attributes ставлю Procedure ID = (Default).

А вот пример использования:
Код: Выделить всё
    Dim func1 As New Callable
    Dim proc2 As New Callable
    Dim x As Long
   
    proc2 1, 2, Now, "hello"
    x = func1(27, 100)
   
    Debug.Print "func1 has returned: "; x


Вот что вывелось:
Код: Выделить всё
Something callable has been called with args:  1  2 17.11.2014 16:54:53 hello.
Something callable has been called with args:  27  100 .
func1 has returned:  53


Как видно, VB6/VBA/VBScript в частности и OLE Automation вообще позволяет любую функцию/процедуру или вообще любую логику обернуть в объект, который с одной стороны будет полноценным COM-объектом (можно наделить его какими-нибудь другими интересными методами и свойствами или научить его поддерживать некие дополнительные COM-интерфейсы для разных нужд, вроде рефлексии), а с другой стороны — с точки зрения языка будет вызывабелен как обыкновенная процедура или функция.

То есть некая абстрактная obj.meth(2, 3) где-нибудь в коде может быть как вызовом нативного метода meth (если он есть), так и обращением к члену meth, который является объектом-функцией, инкапсулирующей в себя какую-то логику.

Это значит, что на уровне кода можно получить объекты-функции такие же как, к примеру, в JavaScript. А если сделать возможность наделять объект в run-time новыми свойствами (о чём и есть этот топик) по мере необходимости (кстати, keks-n по моему заданию уже давно делал такой класс и, кажется, выкладывал здесь), то получится ещё большая иллющия ООП в стиле JavaScript.

Можно будет на ходу создать пустой объект, «присобачить» к нему после этого набор нужных мемберов (обычных свойств) и методов, и получить объект со свойствами и методами.
Код: Выделить всё
Set obj = new JSLikeObject
obj.foo = 33
obj.bar.baz = 23
obj.bar.kaas = 23
obj.meth = compiler.compile("a, b", "MsgBox a+b") ' Возвращат объект, олицетворяющий скомпилированную функцию

obj.meth(2, 3) ' Выведет 5


А потом, при большом желании, можно и как прототип (в стиле JS) использовать этот объект.

То есть используя механику COM/ActiveX и особенность VB, можно устроить жизнь по правилам JS (близкую к ним), но наоборот, к сожалению, не получится.

__________

Более того, возможно даже и такое: можно иметь такую функцию или процедуру, что у неё от рождения есть отождествляющий её функциональный объект, и при этом указатель на функцию и указатель на объект — это одно и то же значение. То есть одно и то же значение можно передавать всем: и тем, кто просто хочет указатель на код (ждёт адрес какого-нибудь callback-а), и тем, кто знает о нашей фишке (некоем интерфейсе ICallable), и сумеет с ним правильно поработать.

Обо всём этом я хотел написать большую статью (и недавно, кажется, даже заикался об этом), но вот только когда?...
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Возможно ли создать динамический объект

Сообщение The trick » 17.11.2014 (Пн) 14:21

Хакер, класс! :D
UA6527P

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 17.11.2014 (Пн) 15:10

Хакер писал(а):Обо всём этом я хотел написать большую статью (и недавно, кажется, даже заикался об этом), но вот только когда?...

Ага, понял идею. Спасибо! А большую статью всё равно с удовольствием почитаю :)

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Возможно ли создать динамический объект

Сообщение ger_kar » 17.11.2014 (Пн) 17:10

The trick писал(а):Хакер, класс! :D
Это точно!!! Для меня было очень познавательно. Немного разовью разыгравшуюся фантазию и добавлю: Можно сделав коллекцию функций методов (члены коллекции могут быть разных классов) передать эту коллекцию некоторому объекту, который заранее не знает ни количества ни суть функций методов, но может просто перебирать коллекцию и вызывать их подряд. Причем можно например первым элементом добавить ссылку на некоторый объект, а далее вложить методы, которые его будут обрабатывать. И последовательность и состав может быть при этом разными, соответственно и на выходе будет разный результат. Т.е логика работы может изменяться прямо в рантайме. Причем сам алгоритм при таком раскладе можно будет даже в БД сохранить :) Прикольно.
Бороться и искать, найти и перепрятать


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот и гости: 4

    TopList