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 ответ

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

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

Другие вопросы по тегам