加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-15 04:04:57 所属栏目:大数据 来源:网络整理
导读:我已经定义了以下内容: 一个方法指针,如果验证正常或错误代码则返回0 TValidationFunc = Function(AParam: TAnObject): integer Of Object; 要执行的功能列表: Functions: TObjectList TValidationFunc; 我在函数列表中放了几个带有此签名的函数. 为了执行
我已经定义了以下内容:

>一个方法指针,如果验证正常或错误代码则返回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 }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读