2016-03-23 5 views
6

Я пытаюсь выяснить, есть ли способ сделать что-то похожее на расширенные функции RTTI от Delphi.FreePascal RTTI. Есть ли способ вызвать метод?

Насколько я знаю, FPC не предоставляет функции RTTI, которые появились в Delphi с Delphi 2010. Но я хотел бы найти способ сделать несколько трюков во время выполнения.

Использование typinfo устройства в FPC я могу делать такие вещи, как:

  • получить объект опубликовал список недвижимости - через getPropList из typinfo блока;
  • получить/установить стоимость опубликованного объекта объекта - через GetPropValue(...): Variant/SetPropValue(...Value: Variant);
  • получить опубликованный метод - через MethodAddres;

Но я не нашел способ сделать такие вещи, как:

  • методы вызова;
  • вызовите конструкторы или создайте объекты;

Update: проблема с конструкторами очень похож на методы один - я хочу, чтобы иметь возможность пройти различные Params в нем:

// 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;

Если я не ошибаюсь, это можно решить с помощью Delphi 2010+ RTTI. Но прежде чем использовать расширенный RTTI Delphi, я хотел бы понять, возможно ли это в FPC.

Другими словами, моя текущая проблема - передать аргументы в процедуру. Я знаю, что это можно сделать, используя эту схему:

type 
    TmyProc = procedure CallMe(x: byte); 
... 
    var proc: TmyProc; 
... 
    proc := pointerToFunc^; 
    proc(0); 

Но мне нужно реализовать, не зная количество и типы параметров (во время компиляции).

Есть несколько ссылок, связанных с темой:

Delphi: Call a function whose name is stored in a string

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; 

это возможно? Или, по крайней мере, что-то похожее на это?

ответ

5
  1. Вы можете вызывать методы, даже не опубликованные, с использованием MethodAddress, но вам решать, чтобы обеспечить правильный список аргументов.
  2. Вы можете вызвать конструкторы с использованием метаклассов (ссылки на классы), пример которых можно увидеть в TCollection: вы передаете класс своего элемента коллекции во время выполнения, а затем его можно создать при необходимости. Определив абстрактный класс с помощью виртуального (и, возможно, абстрактного) конструктора, вы можете найти список аргументов, который вы хотите, например, here.
  3. AFAIK нет способа определить список аргументов во время выполнения, но если вы разработали как методы для вызова, так и сам вызывающий, существует множество способов реализации аналогичного поведения.

Например, вы передаете вариант open array (Array of const), как это сделано в Format(), поэтому количество аргументов и их тип могут отличаться. Но даже имея один и только указатель в качестве аргумента, вы можете пройти столько, сколько хотите, все, что вам нужно сделать, это придумать какой-то класс, к которому он приведет.