是否可以使用TypeKind = tkMethod为TRttiType创建TRttiMethod实例?

时间:2012-02-17 15:05:19

标签: delphi delphi-xe2 rtti

大家好:)这是我在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?我想使用TRttiMethod.CreateImplementation()为事件动态创建eventHandler 或者可能有另一种动态创建方法实现的方法?

PS:想法是创建类似事件链的东西。在编译时,我们不知道事件类型/签名,因此我们可以使用泛型,如TEvenChain< TNotifyEvent>。 Chain在已注册的事件处理程序上有集合,因为我们在编译时不知道处理程序类型,我们必须动态创建它,并且该处理程序只获取其参数并使用它们调用已注册的处理程序。

更新 这里有一些代码(想法是创建事件处理程序链):

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< 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;

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在运行时创建事件处理程序的实现,因为它有关于params类型/计数的信息以及调用所使用的实际事件的约定(在通用中)情况)。

1 个答案:

答案 0 :(得分:4)

带有typekind TRttiType的{​​{1}}将被表示为TkMethod。你无法从中获得TRttiMethodType,因为它不是一种方法;它是一个方法指针,但是如果你看一下TRttiMethod及其TRttiMethodType方法,你应该找到你需要的东西。