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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With