Delphi 如何获取方法指针指向的方法的名称?
我定义了以下内容:Delphi 如何获取方法指针指向的方法的名称?,delphi,delegates,function-pointers,rtti,Delphi,Delegates,Function Pointers,Rtti,我定义了以下内容: 如果验证正常或错误代码,则返回0的方法指针 TValidationFunc = Function(AParam: TAnObject): integer Of Object; 要执行的功能列表: Functions: TObjectList < TValidationFunc>; 如果该函数引发异常,如何在日志中获取原始函数的名称?一种方法是枚举可能的函数,以查找地址与目标匹配的函数。您可以从方法指针解码实例指针。从那里你可以得到类型。然后RTTI可以完成
- 如果验证正常或错误代码,则返回0的方法指针
TValidationFunc = Function(AParam: TAnObject): integer Of Object;
- 要执行的功能列表:
Functions: TObjectList < TValidationFunc>;
如果该函数引发异常,如何在日志中获取原始函数的名称?一种方法是枚举可能的函数,以查找地址与目标匹配的函数。您可以从方法指针解码实例指针。从那里你可以得到类型。然后RTTI可以完成剩下的工作您可以考虑将名称以及方法指针存储在列表中。这将是一个简单易行的方法
我的最后一个想法是,您可以在项目中包含可执行映射,并在那里查找函数。例如,如果您已经使用madExcept、EurekaLog或其他类似工具,那么这将非常简单 最简单的解决方案是——正如David所暗示的那样——将名称与函数指针一起存储,如下所示:TYPE TValidationFunc = Function(AParam: TAnObject): integer Of Object; TFunctions = TDictionary<TValidationFunc,String>; VAR Functions : TFunctions;
然后当你浏览它时:For valid In Functions Doc Begin res := -1; Try res := valid(MyObject); Except On E: Exception Do Log('Error in function '+MethodName(valid)+' : ' + E.Message, TNiveauLog.Error, 'PHVL'); End; Result := Result And (res = 0); End;
通过这种方式,您可以将验证函数与TDictionary中的名称“链接”,这样,当您拥有一个验证函数时,您就可以获得另一个验证函数。好吧,永远不要说永不:-)。此函数将返回作为参数传递的事件的方法名称(格式为.ie.TMainForm.FormCreate)。不幸的是,您不能使用非类型化参数来允许传入任何类型的事件,但必须为您希望能够“解码”的每个方法签名编写特定的例程: 像这样使用它:For valid In Functions.Keys Do Begin Try res := valid(MyObject); Except On E: Exception Do Begin Log('Error in function ' + Functions[valid] + ' : ' + E.Message, TNiveauLog.Error, 'PHVL'); res := -1; End; End; Result := Result And (res = 0); End;
TYPE TValidationFunc = Function(AParam: TAnObject): integer Of Object; TFunctions = TDictionary<TValidationFunc,String>; VAR Functions : TFunctions;
我没有用上面的代码试过,但是用我的主窗体的FormCreate试过了 有一点需要注意:这只适用于已生成RTTI的方法,并且仅适用于Delphi 2010及更高版本(在Delphi 2010及更高版本中,RTTI大量增加了可用数据量)。因此,为了确保它能够工作,您应该将要跟踪的方法放在已发布的部分中,因为这些方法(默认情况下)总是会生成RTTI 如果您希望它更一般,可以使用以下构造:For valid In Functions Doc Begin res := -1; Try res := valid(MyObject); Except On E: Exception Do Log('Error in function '+MethodName(valid)+' : ' + E.Message, TNiveauLog.Error, 'PHVL'); End; Result := Result And (res = 0); End;
然后,您只需要为每个简单调用常规实现的事件编写一个特定的MethodName,如果将其标记为内联,则很有可能它甚至不会引发额外的函数调用,而是直接调用它 顺便说一句:我的回答受到Cosmin一年前在这个问题上给出的代码的严重影响: 如果您的Delphi没有定义NativeInt(不记得具体是什么时候实现的),只需将其定义为:FUNCTION MethodName(CONST M : TMethod) : STRING; OVERLOAD; VAR O : TObject; CTX : TRttiContext; TYP : TRttiType; RTM : TRttiMethod; OK : BOOLEAN; BEGIN O:=M.Data; TRY OK:=O IS TObject; Result:=O.ClassName EXCEPT OK:=FALSE END; IF OK THEN BEGIN CTX:=TRttiContext.Create; TRY TYP:=CTX.GetType(O.ClassType); FOR RTM IN TYP.GetMethods DO IF RTM.CodeAddress=M.Code THEN EXIT(O.ClassName+'.'+RTM.Name) FINALLY CTX.Free END END; Result:=IntToHex(NativeInt(M.Code),SizeOf(NativeInt)*2) END; FUNCTION MethodName(Event : TValidationFunc) : STRING; OVERLOAD; INLINE; BEGIN Result:=MethodName(TMethod(Event)) END;
{$IFNDEF CPUX64 } TYPE NativeInt = INTEGER; {$ENDIF }
为了简化我的示例,我说我将函数存储在列表中,但实际上我的函数在一个类中,因此我可以将函数名存储在我的类中。显然,您在列表中存储的是一个方法指针,而不是一个类。这就是代码所说的。但是你确实可以解码方法指针并获得一个类。我不能增加你答案的分数(这是你名声不好时得到的;),但是非常感谢你快速而好的答案,大卫。欢迎你。我相信你很快就会得到一些选票。我相信其他人会给出更多的答案。谢谢你的答案和代码示例。关键是当我输入Functions.Add(Routine1,'Routine1');我脑子里有个小声音说:老兄,你错过了什么……但是嘿!:-)看看我的另一个答案——这也许是你问题的解决方案?谁说从不?这是我答案的第一段,充实成代码。“谁说从不?”我说了…:-)非常感谢你,HeartWare,这正是我想要的!!!当我看到解决方案时,我同时认为“它没有那么复杂”和“我可能永远也找不到它”。@o.schwab:记住接受你认为对你帮助最大的答案作为解决方案。{$IFNDEF CPUX64 } TYPE NativeInt = INTEGER; {$ENDIF }