微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

delphi – 如何获取方法指针指向的方法的名称?

我已经定义了以下内容

>一个方法指针,如果验证正常或错误代码则返回0

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 }

原文地址:https://www.jb51.cc/delphi/102195.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐