Можно ли создать экземпляр TRttiMethod для TRttiType с TypeKind = tkMethod? - PullRequest
7 голосов
/ 17 февраля 2012

привет всем :) это мой первый вопрос в stackoverflow:)

в Delphi XE2 RTTI у нас есть класс TRttiMethod, и он имеет функцию CreateImplementation(), которая позволяет динамически создавать процедуру или функцию с той же сигнатурой и анонимным методом, что и ее тело.

используя TRttiContext.getMethods() / getMethod() мы можем получить коллекцию методов класса - коллекцию TRttiMethod.

Документация гласит (http://docwiki.embarcadero.com/VCL/en/RTTI.TRttiMethod): не создавайте TRTTiMethod напрямую, а используйте getMethods () для получения его экземпляров.

Итак, если у нас есть экземпляр TRTTIMethod, мы можем динамически создать метод с той же сигнатурой и вызвать его позже.

вопрос в том .. например, у нас есть TNotifyEvent ... TRttiContext.getType(typeinfo(TNotifyEvent)) возвращает TRttiType объект экземпляра, который имеет typekind = tkMethod. мы знаем, что подпись TNotifyEvent является процедурой (отправитель: TObject) объекта;

возможно ли получить TRttiMethod для этого? Я хочу динамически создать eventHandler для события, используя TRttiMethod.CreateImplementation() или может быть есть другой способ динамически создавать реализацию метода?

PS: идея в том, чтобы создать что-то вроде цепочки событий. Во время компиляции мы не знаем тип события / сигнатуру, поэтому мы можем использовать для этого дженерики, например TEvenChain . Цепочка имеет коллекцию зарегистрированных обработчиков событий, поэтому, поскольку мы не знаем тип обработчика во время компиляции, мы должны создать его динамически, и этот обработчик только получает свои параметры и вызывает зарегистрированный обработчик с ними.

Обновление: Вот некоторый код (идея заключается в создании цепочки обработчиков событий):

procedure TMainForm.FormCreate(Sender: TObject);
begin
    FEventChain := TNotifyChain.Create();
    FEventChain.AddHandler(event1);
    FEventChain.AddHandler(event2);   

    TestButton.OnClick := FEventChain.EventHandler;
end;

Event1 & event2 - методы (sender : TObject) формы; это не общий пример (в данном случае T - NotifyEvent / TChain ) TEventChain.EventHandler тоже TNotifyEvent

TNotifyChain is

TNotifyChain = class(TObject)
  strict private
    FEvent : TNotifyEvent;
    FItems : TList<TNotifyEvent>;

    FCtx : TRttiContext;
  public
    procedure TestNotifyHandler(sender : TObject);   virtual; abstract;

    constructor Create();
    procedure AddHandler(eh : TNotifyEvent);
    property  EventHandler : TNotifyEvent read FEvent;
end;
Свойство

EventHandler сопоставлено с переменной FEvent. И FEvent не назначен, так как мы предполагаем, что тип события / обработчика неизвестен.

поэтому в конструкторе мы создаем виртуальный метод с подписью TNotifyEvent и присваиваем его коду FEvent:

constructor TNotifyChain.Create();
var st: TRttiType;
    //et : TRttiMethodType;
    Callback : TMethodImplementationCallback;
    rttiMethod : TRttiMethod;
    m : TMethod;
    mi : TMethodImplementation;
begin
    inherited;
    FItems := TList<TNotifyEvent>.Create();

    FCtx := TRttiContext.Create();

    //et := FCtx.GetType(typeinfo(TNotifyEvent)) as TRttiMethodType;
    st := FCtx.GetType(self.ClassType);


    rttiMethod := st.GetMethod('TestNotifyHandler');

    Callback := procedure(UserData: Pointer;
                        const Args: TArray<TValue>;
                        out Result: TValue)
             var i : integer;
                 e : TMethod;
             begin

                for i := 0 to FItems.Count - 1 do begin
                    e := TMethod(Fitems[i]);
                    result := Invoke(e.Code, args, rttiMethod.CallingConvention, nil);
                end;
             end;


    mi := rttiMethod.CreateImplementation(self, Callback);

    m.data := self;
    m.Code := mi.CodeAddress;
    FEvent := TNotifyEvent(m);
end;

здесь я использую TestNotifyHandler метод для создания фактического обработчика с той же сигнатурой, используя TRttimethod.CreateImplementation()

поэтому, я полагаю, есть способ создать реализацию обработчика событий во время выполнения, используя TRttiMethodType из TNotifyEvent, потому что он содержит информацию о типе / числе параметров и соглашении о вызовах фактического используемого события (в общем случае).

1 Ответ

4 голосов
/ 17 февраля 2012

A TRttiType с typekind TkMethod будет представлено как TRttiMethodType.Вы не можете получить TRttiMethod из этого, потому что это не метод;это указатель на метод, но если вы посмотрите на TRttiMethodType и его метод Invoke, вы должны найти именно то, что вам нужно.

...