FreePascal RTTI. Есть ли способ вызвать метод?
Я пытаюсь выяснить, есть ли способ сделать что-то похожее на расширенные функции Delphi RTTI.
Насколько я знаю, FPC не предоставляет функции RTTI, которые появились в Delphi с Delphi 2010. Но я хотел бы найти способ сделать несколько трюков во время выполнения.
С помощью typinfo
В блоке FPC я могу делать такие вещи как:
- получить список опубликованных свойств объекта - через
getPropList
отtypinfo
единица измерения; - получить / установить значение опубликованного свойства объекта - через
GetPropValue(...): Variant
/SetPropValue(...Value: Variant)
; - получить опубликованный метод - через
MethodAddres
;
Но я не нашел способ сделать такие вещи, как:
- вызывать методы;
- вызывать конструкторы или создавать объекты;
Обновление: проблема с конструкторами во многом похожа на методы один - я хочу, чтобы в нем был способ передавать различные параметры:
// concept of code
type
TClass = class of TObject;
TMyClass1 = class
public
constructor Create(Param1: Integer; Param2: string); override;
end;
TMyClass2 = class
public
constructor Create(ObjectParam: Object); override;
end;
TParams = array of Variant;
var
Classes: array of TClass
Instances: array of Object;
ParamArray: array of TParams;
...
For I := 0 to Count-1 do
begin
LocalConstructor := @(Classes[I].Create);
Instances[I] := CallConstructor(LocalConstructor, ParamArray[I]);
end;
Поэтому мне нужно вызвать конструктор, не зная его подписи.
Поэтому моя проблема - вызвать метод Object и передать ему некоторые параметры. Это может выглядеть как function CallMethod(Instance: Object; MethodName: String; Params: array of Variant): Variant;
Если я не ошибаюсь, это можно решить с помощью RTTI Delphi 2010+. Но прежде чем использовать расширенный RTTI в Delphi, я хотел бы понять, возможно ли это в FPC.
Другими словами, моя текущая проблема - передать аргументы рутине. Я знаю, что это можно сделать с помощью этой схемы:
type
TmyProc = procedure CallMe(x: byte);
...
var proc: TmyProc;
...
proc := pointerToFunc^;
proc(0);
Но мне нужно реализовать это, не зная количества и типов параметров (во время компиляции).
Есть несколько ссылок, связанных с темой:
Delphi: вызов функции, имя которой хранится в строке
http://www.swissdelphicenter.ch/torry/showcode.php?id=1745
Вторая статья ( http://www.swissdelphicenter.ch/torry/showcode.php?id=1745) описывает способ передачи аргументов в процедуру, импортированную из DLL по имени. Это почти то, что мне нужно, я полагаю. Но я не уверен, что это надежно.
Может быть, есть какая-нибудь библиотека, которая реализует эти вещи, используя "старый" модуль typinfo (без модуля RTTI)?
Также меня интересует способ создания неких универсальных обработчиков событий - процедур, которые можно назначать разным событиям (с разными наборами параметров), например:
procedure myEventHandler(params: array of variant);
...
Button.OnClick := myEventHandler;
Button.OnMouseMove := myEventHandler;
Это возможно? Или хотя бы что-то похожее на это?
1 ответ
- Вы можете вызывать методы, даже не опубликованные, используя MethodAddress, но вы должны убедиться в правильности списка аргументов.
- Вы можете вызывать конструкторы, используя метаклассы (ссылки на классы), пример этого можно увидеть в TCollection: вы передаете класс своего элемента коллекции во время выполнения, а затем он может быть создан при необходимости. Определив абстрактный класс с помощью виртуального (и, вероятно, абстрактного) конструктора, вы можете придумать список аргументов, который вам нужен, например, здесь.
- AFAIK Нет способа определить список аргументов во время выполнения, но если вы разрабатываете как методы для вызова, так и для самого вызывающего, есть много способов реализовать похожее поведение.
Например, вы передаете вариант open array ( Array of const), как это делается в Format(), поэтому число аргументов и их тип могут различаться. Но даже имея один-единственный указатель в качестве аргумента, вы точно можете передать столько, сколько захотите, все, что вам нужно сделать, - это придумать какой-то класс, к которому он приведет.