ter*_*ran 7 delphi rtti delphi-xe2
大家好:)这是我在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的签名是对象的过程(sender:TObject);
有可能得到TRttiMethod
这个吗?我想为事件动态创建eventHandler,TRttiMethod.CreateImplementation()
或者可能有另一种方法动态创建方法实现?
PS:想法是创建类似事件链的东西.在编译时,我们不知道事件类型/签名,因此我们可以使用泛型,如TEvenChain <TNotifyEvent>.Chain在已注册的事件处理程序上有集合,因为我们在编译时不知道处理程序类型,我们必须动态创建它,并且该处理程序只获取其参数并使用它们调用已注册的处理程序.
更新: 这里是一些代码(想法是创建事件处理程序链):
procedure TMainForm.FormCreate(Sender: TObject);
begin
FEventChain := TNotifyChain.Create();
FEventChain.AddHandler(event1);
FEventChain.AddHandler(event2);
TestButton.OnClick := FEventChain.EventHandler;
end;
Run Code Online (Sandbox Code Playgroud)
Event1
&event2
是(sender : TObject)
形式的方法; 它不是一般示例(T在这种情况下是NotifyEvent/TChain <TNotifyEvent>)
TEventChain.EventHandler
是TNotifyEvent
太
TNotifyChain
是
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;
Run Code Online (Sandbox Code Playgroud)
EventHandler
property被映射到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;
Run Code Online (Sandbox Code Playgroud)
在这里,我使用TestNotifyHandler
方法创建具有相同签名的实际处理程序TRttimethod.CreateImplementation()
所以我想,有一种方法可以在运行时使用TRttiMethodType
from 创建事件处理程序的实现,TNotifyEvent
因为它有关于params类型/计数的信息和调用所使用的实际事件的约定(在通用情况下).
TRttiType
具有 typekind 的ATkMethod
将被表示为 a TRttiMethodType
。你无法TRttiMethod
从中得到 a,因为它不是一个方法;它是一个方法指针,但是如果你看一下TRttiMethodType
它的Invoke
方法,你应该找到你所需要的。