首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >方法指针的RTTI信息

方法指针的RTTI信息
EN

Stack Overflow用户
提问于 2013-02-05 10:16:55
回答 1查看 3.8K关注 0票数 3

能否获得关于TMethod的RTTI信息?

我可以通过

代码语言:javascript
复制
Instance := TObject(Method.Data);

所以我可以得到实例的RTTI类型,但是如何获得正确的TRttiMethod呢?我想检查使用方法指针传入的方法的属性。

EN

回答 1

Stack Overflow用户

发布于 2013-02-05 10:36:47

这种方法在理论上是有效的,在实践中有一个很好的改变,但是有几件事情可能会阻止您获得TRttiMethod

  • TMethod记录上写的是Data: Pointer,而不是TObject。这意味着可能会有其他东西,而不是TObject作为Data!这是一个严重的问题,因为如果Data不是TObject,那么尝试从其中提取RTTI将导致运行时错误。
  • 并非所有方法都有RTTI。默认情况下,私有区域中的方法没有RTTI,可以使用{$RTTI}停止为公共成员或已发布成员生成RTTI。

这两个问题对于我们在Delphi中通常使用的事件实现类型(双击对象检查器中事件的名称并填写代码)来说不会是一个问题,但我还是认为您不是在谈论"vanila“实现。没有多少人会用属性来装饰默认的事件处理程序!

演示上述所有内容的代码:

代码语言:javascript
复制
program Project15;

{$APPTYPE CONSOLE}

uses
  SysUtils, RTTI;

type
  // Closure/Event type
  TEventType = procedure of object;

  // An object that has a method compatible with the declaration above
  TImplementation = class
  private
    procedure PrivateImplementation;
  public
    procedure HasRtti;

    procedure GetPrivateImpEvent(out Ev:TEventType);
  end;

  TRecord = record
    procedure RecordProc;
  end;

  // an object that has a compatible method but provides no RTTI
  {$RTTI EXPLICIT METHODS([])}
  TNoRttiImplementation = class
  public
    procedure NoRttiAvailable;
  end;

procedure TImplementation.GetPrivateImpEvent(out Ev:TEventType);
begin
  Ev := PrivateImplementation;
end;

procedure TImplementation.HasRtti;
begin
  WriteLn('HasRtti');
end;

procedure TNoRttiImplementation.NoRttiAvailable;
begin
  WriteLn('No RTTI Available');
end;

procedure TRecord.RecordProc;
begin
  WriteLn('This is written from TRecord.RecordProc');
end;

procedure TImplementation.PrivateImplementation;
begin
  WriteLn('PrivateImplementation');
end;

procedure TotalyFakeImplementation(Instance:Pointer);
begin
  WriteLn('Totaly fake implementation, TMethod.Data is nil');
end;

procedure SomethingAboutMethod(X: TEventType);
var Ctx: TRttiContext;
    Typ: TRttiType;
    Method: TRttiMethod;
    Found: Boolean;
begin
  WriteLn('Invoke the method to prove it works:');
  X;
  // Try extract information about the event
  Ctx := TRttiContext.Create;
  try
    Typ := Ctx.GetType(TObject(TMethod(X).Data).ClassType);
    Found := False;
    for Method in Typ.GetMethods do
      if Method.CodeAddress = TMethod(X).Code then
      begin
        // Got the Method!
        WriteLn('Found method: ' + Typ.Name + '.' + Method.Name);
        Found := True;
      end;
    if not Found then
      WriteLn('Method not found.');
  finally Ctx.Free;
  end;
end;

var Ev: TEventType;
    R: TRecord;

begin
  try
    try
      WriteLn('First test, using a method that has RTTI available:');
      SomethingAboutMethod(TImplementation.Create.HasRtti);
      WriteLn;

      WriteLn('Second test, using a method that has NO rtti available:');
      SomethingAboutMethod(TNoRttiImplementation.Create.NoRttiAvailable);
      WriteLn;

      WriteLn('Third test, private method, default settings:');
      TImplementation.Create.GetPrivateImpEvent(Ev);
      SomethingAboutMethod(Ev);
      WriteLn;

      WriteLn('Assign event handler using handler from a record');
      try
        SomethingAboutMethod(R.RecordProc);
      except on E:Exception do WriteLn(E.Message);
      end;
      WriteLn;

      WriteLn('Assign event handler using static procedure');
      try
        TMethod(Ev).Data := nil;
        TMethod(Ev).Code := @TotalyFakeImplementation;
        SomethingAboutMethod(Ev);
      except on E:Exception do WriteLn(E.Message);
      end;
      WriteLn;

    except
      on E: Exception do Writeln(E.ClassName, ': ', E.Message);
    end;
  finally ReadLn;
  end;
end.
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14705071

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档