方法指针的RTTI信息 [英] RTTI information for method pointer
问题描述
可以获取关于 TMethod
的RTTI信息吗?
Is it possible to obtain RTTI information about a TMethod
?
我可以通过
Instance := TObject(Method.Data);
所以我可以获得实例的RTTI类型,但是如何获得正确的 TRttiMethod
?我想检查使用方法指针传递的方法的属性。
so I can get the RTTI type of the instance, but how can I get the correct TRttiMethod
? I want to check for attributes on a method passed in using a method pointer.
推荐答案
这种方法在理论上有效,有一个良好的变化将会在实践中起作用,但有几件事情可能会阻止您持有 TRttiMethod
。
This approach works in theory, and there's a good change it will work in practice, but there are a couple of things that could prevent you from getting hold of the TRttiMethod
.
-
TMethod
记录说数据:指针
,而不是$ code> TObject 。这意味着可能会有另外一个可能的东西TObject
作为数据
!这是一个严重的问题,因为如果Data
不是TObject
,那么尝试从中提取RTTI将会导致运行时错误。 - 并非所有方法都具有RTTI。默认情况下,私人区域中的方法没有RTTI,并且可以使用
{$ RTTI}
停止为公共或已发布成员生成RTTI。
- The
TMethod
record saysData: Pointer
, notTObject
. This implies there might be a possibility of having something other then anTObject
as theData
! This is a serious issue, because if theData
is notTObject
, then attempting to extract RTTI from it is going to result in runtime errors. - Not all methods have RTTI. By default methods in the private area do not have RTTI, and one can use the
{$RTTI}
to stop generating RTTI for public or published members as well.
这两个问题对于我们在Delphi中的常见类型的事件实现来说不会是一个问题(双击事件在Object中的名称检查员并填写代码),但是再一次,我不认为你在谈论vanila实现。没有多少人使用Attributes来装饰默认的事件处理程序!
Those two issues would not be a problem for the usual type of event implementations we have in Delphi (double-click on the name of the event in Object Inspector and fill in the code), but then again I don't think you're talking about "vanila" implementations. Not many people would decorate the default event handlers with Attributes!
演示所有上述代码:
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.
这篇关于方法指针的RTTI信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!