Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to create TRttiMethod instance for TRttiType with TypeKind=tkMethod?

hi all :) it is my first question at stackoverflow :)

in Delphi XE2 RTTI we have TRttiMethod class and it has function CreateImplementation() wich allows to dynamically create procedure or function with the same signature and a anonimous method as its body.

using TRttiContext.getMethods()/getMethod() we can get collection of class methods - collection of TRttiMethod.

documentation says (http://docwiki.embarcadero.com/VCL/en/RTTI.TRttiMethod) do not to create TRTTiMethod directly, and use getMethods() to get its instances.

so, if we have TRTTIMethod instance, we can dynamically create method with the same signature and invoke it later.

the question is.. for example, we have TNotifyEvent... TRttiContext.getType(typeinfo(TNotifyEvent)) returns TRttiType instance object wich has typekind = tkMethod. we know that signature of TNotifyEvent is procedure (sender : TObject) of object;

is it possible to get TRttiMethod for this? I want to dynamically create eventHandler for the event using TRttiMethod.CreateImplementation() or may be there is another way to dynamically create method implementation?

PS: idea is to create something like Event Chain. At compile time we don't know event type/signature, so we can use generics for this like TEvenChain<TNotifyEvent>. Chain has collection on registered event handlers, so because we don't know handler type at compile time we have to create it dynamically, and that handler only gets its parameters and calls registered handler with them.

update: here is some code (idea is to create event handlers chain):

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

    TestButton.OnClick := FEventChain.EventHandler;
end;

Event1 & event2 are methods(sender : TObject) of form; it is not generic example (T in this case is NotifyEvent/TChain<TNotifyEvent>) TEventChain.EventHandler is TNotifyEvent too

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 property is mapped to FEvent variable. And FEvent is not assigned as we assume that type of event/handler is unknown.

so in constructor we create virtual method with TNotifyEvent signature and assign its code to 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;

here I use TestNotifyHandler method to create actual handler with the same signature using TRttimethod.CreateImplementation()

so I suppose, there is a way to create implementation of event handler at runtime using TRttiMethodType from TNotifyEvent because it has info about params type/count and calling convention of actual event used (in generic case).

like image 503
teran Avatar asked Feb 17 '12 15:02

teran


1 Answers

A TRttiType with typekind TkMethod is going to be represented as a TRttiMethodType. You can't get a TRttiMethod from it, because it's not a method; it's a method pointer, but if you take a look at TRttiMethodType and its Invoke method, you should find exactly what you need.

like image 72
Mason Wheeler Avatar answered Oct 01 '22 02:10

Mason Wheeler