我已经定义了以下内容:
TValidationFunc = Function(AParam: TAnObject): integer Of Object;
>要执行的功能列表:
Functions: TObjectList < TValidationFunc>;
为了执行它们,我执行:
For valid In Functions Do Begin res := -1; Try res := valid(MyObject); Except On E: Exception Do Log('Error in function ??? : ' + E.Message,TNiveauLog.Error,'PHVL'); End; Result := Result And (res = 0); End;
解决方法
好吧,永远不要说永远:-).对于将其作为参数传递的事件,此函数将返回方法名称(格式为< ClassType>.< MethodName> ie.TMainForm.FormCreate).遗憾的是,您不能使用无类型参数来允许传入任何类型的事件,但必须为您希望能够“解码”的每个方法签名编写特定例程:
FUNCTION MethodName(Event : TValidationFunc) : STRING; VAR M : TMethod ABSOLUTE Event; 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;
像这样用它:
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,'PHVL'); End; Result := Result And (res = 0); End;
我没有用上面的代码试过它,但是用我的MainForm的FormCreate尝试过.
有一点需要注意:这只适用于生成RTTI的方法,而且只适用于Delphi 2010及更高版本(它们大大增加了RTTI可用的数据量).因此,为了确保它有效,您应该将要跟踪的方法放在PUBLISHED部分中,因为这些方法始终(默认情况下)将生成RTTI.
如果你想要它更一般,你可以使用这个结构:
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;
然后你只需要为每个只调用一般实现的事件编写一个特定的MethodName,如果你把它标记为INLINE,它很可能甚至不会产生额外的函数调用,而是直接调用它.
顺便说一句:我的答复很大程度上受到Cosmin Prund一年前在这个问题中给出的代码的影响:RTTI information for method pointer
如果您的Delphi没有定义NativeInt(无法记住它们何时实现它),只需将其定义为:
{$IFNDEF cpuX64 } TYPE NativeInt = INTEGER; {$ENDIF }