AJ.*_*AJ. 6 delphi rtti class-helpers
让我们说我有一个示例类助手
TSampleClassHelper = class helper for TSampleClass
public
procedure SomeHelper;
end;
Run Code Online (Sandbox Code Playgroud)
我做以下事情:
var
obj :TSampleClass;
begin
obj:=TSampleClass.Create;
obj.SomeHelper;
end;
Run Code Online (Sandbox Code Playgroud)
这按预期工作.
但是,如何使用RTTI来调用辅助方法呢?以下似乎不起作用,GetMethod返回nil.
var
obj :TSampleClass;
ctx :TRTTIContext;
rtype :TRTTIType;
rmethod :TRTTIMethod;
begin
obj:=TSampleClass.Create;
rtype:=ctx.GetType(obj.ClassType);
rmethod:=rtype.GetMethod('SomeHelper'); // rmethod is nil !
end;
Run Code Online (Sandbox Code Playgroud)
那么RTTI不适用于类助手中定义的方法吗?有没有办法解决?
谢谢.
您的代码返回nil方法的原因是对象的类型不包含名为的方法SomeHelper.包含该方法的类型是帮助程序类型.
所以,你可以写这个将返回一个非零方法:
obj:=TSampleClass.Create;
rtype:=ctx.GetType(TypeInfo(TSampleClassHelper));
rmethod:=rtype.GetMethod('SomeHelper');
Run Code Online (Sandbox Code Playgroud)
当然,你应该立即看到第一个问题,即使用编译时指定的类型,TSampleClassHelper.我们可以TSampleClassHelper根据实例的类型使用RTTI 在运行时发现吗?不,我们不能,我将在下面解释.
即使我们将其放在一边,据我所知,也无法使用RTTI调用该方法.如果您调用块中rmethod.Invoke(obj, [])的代码,TRttiInstanceMethodEx.DispatchInvoke则尝试调用辅助方法.它阻止它,因为它规定实例的类型与方法的类不兼容.相关代码是:
if (cls <> nil) and not cls.InheritsFrom(TRttiInstanceType(Parent).MetaclassType) then
raise EInvalidCast.CreateRes(@SInvalidCast);
Run Code Online (Sandbox Code Playgroud)
好吧,您可以获取辅助方法的代码地址,rmethod.CodeAddress但是您需要找到一些其他方法来调用该方法.很容易将它转换为具有适当签名的方法并调用它.但rmethod.CodeAddress无论如何,为什么还要烦恼呢?为什么不在TSomeHelperClass.SomeMethod循环中使用和剪切RTTI?
讨论
辅助分辨率是根据编译点的活动帮助程序静态执行的.一旦尝试使用RTTI调用辅助方法,就没有活动的帮助器.你早就完成编译了.所以你必须决定使用哪个助手类.此时,您不需要RTTI.
这里的基本问题是类助手方法解析基本上是使用编译器上下文执行的静态过程.由于运行时没有编译器上下文,因此无法使用RTTI执行类帮助程序方法解析.
有关这方面的更多信息,请阅读Allen Bauer的答案:使用RTTI在运行时查找Delphi中的所有类助手?