如何确定 TRttiMethod 是否为函数

发布于 2024-09-26 07:46:53 字数 4681 浏览 5 评论 0原文

我需要确定 TRttiMethod 是否是一个函数

到目前为止,

Function IsFunction(QualifiedName,MethodName:string):Boolean;
Var
  ctx     : TRttiContext;
  lType   : TRttiType;
  lMethod : TRttiMethod;
Begin
    result:=false;
    ctx := TRttiContext.Create;
    lType:=ctx.FindType(QualifiedName);
    if Assigned(lType) then
    begin
       lMethod:=lType.GetMethod(MethodName);
         if Assigned(lMethod) then
           Result:=(lMethod.ReturnType<>nil); //in this line the exception is raised
    end;
End;

,我编写了这个函数,但是这个函数因这个异常而失败 没有足够的 RTTI 来支持此操作。 当我测试以下

IsFunction('SysUtils.Exception','CreateFmt')

这些类和方法时也失败时,

SysUtils.Exception -> CreateFmt
SysUtils.Exception -> CreateResFmt
SysUtils.Exception -> CreateResFmt
SysUtils.Exception -> CreateFmtHelp
SysUtils.Exception -> CreateResFmtHelp
SysUtils.Exception -> CreateResFmtHelp
SysUtils.TEncoding -> Convert
SysUtils.TEncoding -> Convert
SysUtils.TEncoding -> GetBufferEncoding
SysUtils.TEncoding -> GetBufferEncoding
SysUtils.TEncoding -> GetByteCount
SysUtils.TEncoding -> GetByteCount
SysUtils.TEncoding -> GetByteCount
SysUtils.TEncoding -> GetByteCount
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetCharCount
SysUtils.TEncoding -> GetCharCount
SysUtils.TEncoding -> GetChars
SysUtils.TEncoding -> GetChars
SysUtils.TEncoding -> GetChars
SysUtils.TEncoding -> GetPreamble
SysUtils.TEncoding -> GetString
SysUtils.TEncoding -> GetString
SysUtils.TMBCSEncoding -> GetPreamble
SysUtils.TUTF8Encoding -> GetPreamble
SysUtils.TUnicodeEncoding -> GetPreamble
SysUtils.TBigEndianUnicodeEncoding -> GetPreamble
Rtti.TRttiMethod -> Invoke
Rtti.TRttiMethod -> Invoke
Rtti.TRttiMethod -> Invoke
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> AddRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> AddRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> AddRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> InsertRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> InsertRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> InsertRange
Generics.Collections.TArray -> Sort
Generics.Collections.TArray -> Sort
Generics.Collections.TArray -> Sort
Generics.Collections.TArray -> BinarySearch
Generics.Collections.TArray -> BinarySearch
Generics.Collections.TArray -> BinarySearch

我编写了这个小应用程序来检查此行为

program ProjectTest;

{$APPTYPE CONSOLE}

uses
  Rtti,
  SysUtils;

Function IsFunction(QualifiedName,MethodName:string):Boolean;
Var
  ctx     : TRttiContext;
  lType   : TRttiType;
  lMethod : TRttiMethod;
Begin
    result:=false;
    ctx := TRttiContext.Create;
    lType:=ctx.FindType(QualifiedName);
    if Assigned(lType) then
    begin
       lMethod:=lType.GetMethod(MethodName);
       try
         if Assigned(lMethod) then
           Result:=(lMethod.ReturnType<>nil);
       except on e : exception do
           Writeln(Format('%s %s -> %s',[e.Message,QualifiedName,MethodName]));
       end;
    end;
End;


var
  ctx     : TRttiContext;
  lType   : TRttiType;
  lMethod : TRttiMethod;
begin
  try
    ctx := TRttiContext.Create;
    for lType in  ctx.GetTypes do
       for lMethod in lType.GetDeclaredMethods do
         IsFunction(lType.QualifiedName,lMethod.Name);
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

,这是确定 TRttiMethod< 的正确方法/code> 是一个函数吗?

更新

感谢@Barry的建议,我重写了函数以避免异常,但这并没有解决如何确定TRttiMethod是否是函数的问题由于 RTTI 当前的限制。

function IsFunction(lType : TRttiType;MethodName:string):Boolean;
Var
  ctx     : TRttiContext;
  lMethod : TRttiMethod;
Begin
    result:=false;
    if Assigned(lType) then
    begin
       lMethod:=lType.GetMethod(MethodName);
         if Assigned(lMethod) then
           if lMethod.HasExtendedInfo then
            Result:= (lMethod.MethodKind in [mkFunction,mkClassFunction]) //you can be 100 % sure, wich this is a function or not
           else // sorry but the RTTI does not provide this information when the TRttiMethod contains parameters or an resultype that are not supported by the RTTI
             Result:=False;
    end;
End;

I need determine if a TRttiMethod is a function

so far, i wrote this function

Function IsFunction(QualifiedName,MethodName:string):Boolean;
Var
  ctx     : TRttiContext;
  lType   : TRttiType;
  lMethod : TRttiMethod;
Begin
    result:=false;
    ctx := TRttiContext.Create;
    lType:=ctx.FindType(QualifiedName);
    if Assigned(lType) then
    begin
       lMethod:=lType.GetMethod(MethodName);
         if Assigned(lMethod) then
           Result:=(lMethod.ReturnType<>nil); //in this line the exception is raised
    end;
End;

but this function fail with this exception
Insufficient RTTI available to support this operation. when i test the Following

IsFunction('SysUtils.Exception','CreateFmt')

also fails with these classes and methods

SysUtils.Exception -> CreateFmt
SysUtils.Exception -> CreateResFmt
SysUtils.Exception -> CreateResFmt
SysUtils.Exception -> CreateFmtHelp
SysUtils.Exception -> CreateResFmtHelp
SysUtils.Exception -> CreateResFmtHelp
SysUtils.TEncoding -> Convert
SysUtils.TEncoding -> Convert
SysUtils.TEncoding -> GetBufferEncoding
SysUtils.TEncoding -> GetBufferEncoding
SysUtils.TEncoding -> GetByteCount
SysUtils.TEncoding -> GetByteCount
SysUtils.TEncoding -> GetByteCount
SysUtils.TEncoding -> GetByteCount
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetBytes
SysUtils.TEncoding -> GetCharCount
SysUtils.TEncoding -> GetCharCount
SysUtils.TEncoding -> GetChars
SysUtils.TEncoding -> GetChars
SysUtils.TEncoding -> GetChars
SysUtils.TEncoding -> GetPreamble
SysUtils.TEncoding -> GetString
SysUtils.TEncoding -> GetString
SysUtils.TMBCSEncoding -> GetPreamble
SysUtils.TUTF8Encoding -> GetPreamble
SysUtils.TUnicodeEncoding -> GetPreamble
SysUtils.TBigEndianUnicodeEncoding -> GetPreamble
Rtti.TRttiMethod -> Invoke
Rtti.TRttiMethod -> Invoke
Rtti.TRttiMethod -> Invoke
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> AddRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> AddRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> AddRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> InsertRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> InsertRange
Generics.Collections.TList<Rtti.TMethodImplementation.TParamLoc> -> InsertRange
Generics.Collections.TArray -> Sort
Generics.Collections.TArray -> Sort
Generics.Collections.TArray -> Sort
Generics.Collections.TArray -> BinarySearch
Generics.Collections.TArray -> BinarySearch
Generics.Collections.TArray -> BinarySearch

i wrote this small app to check this behavior

program ProjectTest;

{$APPTYPE CONSOLE}

uses
  Rtti,
  SysUtils;

Function IsFunction(QualifiedName,MethodName:string):Boolean;
Var
  ctx     : TRttiContext;
  lType   : TRttiType;
  lMethod : TRttiMethod;
Begin
    result:=false;
    ctx := TRttiContext.Create;
    lType:=ctx.FindType(QualifiedName);
    if Assigned(lType) then
    begin
       lMethod:=lType.GetMethod(MethodName);
       try
         if Assigned(lMethod) then
           Result:=(lMethod.ReturnType<>nil);
       except on e : exception do
           Writeln(Format('%s %s -> %s',[e.Message,QualifiedName,MethodName]));
       end;
    end;
End;


var
  ctx     : TRttiContext;
  lType   : TRttiType;
  lMethod : TRttiMethod;
begin
  try
    ctx := TRttiContext.Create;
    for lType in  ctx.GetTypes do
       for lMethod in lType.GetDeclaredMethods do
         IsFunction(lType.QualifiedName,lMethod.Name);
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

which is the correct way to determine if an TRttiMethod is a function?

UPDATE

Thanks to the @Barry suggestions, i rewrote the function to avoid the exception, however this does not solve the problem of how to determine if a TRttiMethod is a function or not due to current limitations of the RTTI.

function IsFunction(lType : TRttiType;MethodName:string):Boolean;
Var
  ctx     : TRttiContext;
  lMethod : TRttiMethod;
Begin
    result:=false;
    if Assigned(lType) then
    begin
       lMethod:=lType.GetMethod(MethodName);
         if Assigned(lMethod) then
           if lMethod.HasExtendedInfo then
            Result:= (lMethod.MethodKind in [mkFunction,mkClassFunction]) //you can be 100 % sure, wich this is a function or not
           else // sorry but the RTTI does not provide this information when the TRttiMethod contains parameters or an resultype that are not supported by the RTTI
             Result:=False;
    end;
End;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

指尖凝香 2024-10-03 07:46:53

您可以检查 TRttiMethod.HasExtendedInfo 以避免异常。如果尝试访问仅当 HasExtendedInfo 返回 True 时数据才可用的属性,该类会引发异常。

您可以考虑根据需要检查 MethodKind 属性,看看它是 mkFunction 还是 mkClassFunction 等。如果 HasExtendedInfoFalseMethodKind 返回 mkProcedure

You can check TRttiMethod.HasExtendedInfo to avoid the exception. The class throws an exception for attempts to access properties for which data is only available if HasExtendedInfo returns True.

You could consider checking the MethodKind property to see if it's mkFunction or mkClassFunction, etc. as needed. MethodKind returns mkProcedure if HasExtendedInfo is False.

歌入人心 2024-10-03 07:46:53

在大多数情况下,您的 IsFunction 函数应该可以正常工作。但有些函数没有为其生成 RTTI,因为它们的参数包含没有可用 RTTI 的类型,例如 TBytesarray of const。但对于大多数功能,您的功能都可以工作。 我只是希望这些遗漏能够由下一个版本。

Your IsFunction function should work fine in most cases. But some functions don't have RTTI generated for them, because their parameters include types that don't have RTTI available, such as TBytes or array of const. But for most functions, your function will work. I just hope that the omissions get filled in by the next version.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文