gpt4 book ai didi

delphi - 方法指针的 RTTI 信息

转载 作者:行者123 更新时间:2023-12-03 15:54:50 25 4
gpt4 key购买 nike

是否可以获取有关 TMethod 的 RTTI 信息?

我可以通过以下方式获取实例

Instance := TObject(Method.Data);

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

最佳答案

这种方法在理论上是有效的,并且有一个很好的改变,它在实践中也能发挥作用,但是有一些事情可能会阻止您掌握 TRttiMethod

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

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

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

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.

关于delphi - 方法指针的 RTTI 信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14705071/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com