是否可以使用 Rtti 确定 aTRttiMethod
是标记为overload
还是override
?abstract
提前致谢。
重载:我认为没有 RTTI 标志,但您可以检查是否有多个同名方法。这并不完美,但它可能与您将获得的一样接近。
覆盖:首先,确保方法是虚拟的。(或动态或消息调度。)然后检查类的祖先是否有其他具有相同名称和 VirtualIndex 属性的方法。
摘要:在 rtti.pas 的实现部分的深处,带有一堆方法数据标志,称为mfAbstract
,定义为1 shl 7;
。没有引用这个的代码,但它是在编译器生成的 RTTI 中实现的。当您有该方法的 TRttiMethod 参考时,您可以像这样测试它:
IsVirtual := PVmtMethodExEntry(method.Handle).Flags and (1 shl 7) <> 0;
PVmtMethodExEntry 在TypInfo
单元中声明,因此您需要使用它才能工作。
如果它仍然很重要......我这样检查:
1. function GetCloneProc: TRttiMethod;
2. var
3. methods: TArray<TRttiMethod>;
4. parameters: TArray<TRttiParameter>;
5. begin
6. methods := BaseType.GetDeclaredMethods;
7. for Result in methods do
8. begin
9. if (Result.MethodKind = mkProcedure) and (Result.Name = 'CloneTo') and
10. (Result.DispatchKind = dkStatic) and not Result.IsClassMethod then
11. begin
12. parameters := Result.GetParameters;
13. if (Length(parameters) = 1) and (parameters[0].Flags = [pfAddress]) and
14. (parameters[0].ParamType.TypeKind = tkClass) and
15. ((parameters[0].ParamType as TRttiInstanceType).MetaclassType = (BaseType as TRttiInstanceType).MetaclassType) then
16. Exit;
17. end;
18. end;
19. Result := nil;
20. end;
您应该注意第 10 行。虚拟或动态方法分别具有 DispatchKinddkVtable
和dkDynamic
。因此,如果方法标记为abstract
它必须具有其中之一。同时为了避免得到class static
方法,我使用第二个条件:not TRttiMethod.IsClassMethod
另请参阅 System.Rtti:
TDispatchKind = (dkStatic, dkVtable, dkDynamic, dkMessage, dkInterface);
您可以自行决定处理此枚举。
关于“覆盖”:看TStream.Seek
,也许你会在那里找到对你有用的东西。
关于“过载”:上面@mason-wheeler 的答案在这种情况下看起来相当不错。