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

delphi – TRttiMethod.Invoke函数在重载方法中不起作用?

发布时间:2020-12-15 04:27:51 所属栏目:大数据 来源:网络整理
导读:我正在使用 TRttiMethod.Invoke函数创建一个类的实例,但是当构造函数或方法重载时,rtti不会调用正确的方法. 我写了一个示例应用来说明我的问题. program ProjectFoo;{$APPTYPE CONSOLE}{$R *.res}uses Rtti,System.SysUtils;type TFoo=class public construc
我正在使用 TRttiMethod.Invoke函数创建一个类的实例,但是当构造函数或方法重载时,rtti不会调用正确的方法.

我写了一个示例应用来说明我的问题.

program ProjectFoo;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Rtti,System.SysUtils;

type
  TFoo=class
  public
    constructor Create(Value :  Integer);overload;
    constructor Create(const Value :  string);overload;
    function Bar(value : integer) : Integer; overload;
    function Bar(const value : string) : string; overload;
  end;

{ TFoo }

constructor TFoo.Create(Value: Integer);
begin
   Writeln(Value);
end;

function TFoo.Bar(value: integer): Integer;
begin
   Writeln(Value);
   Result:=value;
end;

function TFoo.Bar(const value: string): string;
begin
   Writeln(Value);
   Result:=value;
end;


constructor TFoo.Create(const Value: string);
begin
   Writeln(Value);
end;

var
 c : TRttiContext;
 t : TRttiInstanceType;
 r : TValue;
begin
  try
   c := TRttiContext.Create;
   t := (c.GetType(TFoo) as TRttiInstanceType);
   r := t.GetMethod('Create').Invoke(t.MetaclassType,[444]);//this works 
   //r := t.GetMethod('Create').Invoke(t.MetaclassType,['hello from constructor string']);//this fails : EInvalidCast: Invalid class typecast
   t.GetMethod('Bar').Invoke(r,[1]);// this works
   //t.GetMethod('Bar').Invoke(r,['Hello from bar']); //this fails : EInvalidCast: Invalid class typecast
  except
    on E: Exception do
      Writeln(E.ClassName,': ',E.Message);
  end;
   readln;
end.

这是一个RTTI错误?或者存在使用RTTI调用类的重载方法的另一种方法?

解决方法

TRttiMethod.Invoke方法没有任何问题,您的问题位于 GetMethod.此函数在内部调用 TRttiType.GetMethods并检索指向第一个方法的指针,该指针与作为参数传递的名称匹配.因此,当您执行此代码t.GetMethod(‘Create’)时,您总是会获得指向同一方法的指针.

要执行构造函数或其他方法的重载版本,必须根据参数解析要执行的方法地址,然后调用TRttiMethod.Invoke函数.

检查此示例功能.

function RttiMethodInvokeEx(const MethodName:string; RttiType : TRttiType; Instance: TValue; const Args: array of TValue): TValue;
var
 Found   : Boolean;
 LMethod : TRttiMethod;
 LIndex  : Integer;
 LParams : TArray<TRttiParameter>;
begin
  Result:=nil;
  LMethod:=nil;
  Found:=False;
  for LMethod in RttiType.GetMethods do
   if SameText(LMethod.Name,MethodName) then
   begin
     LParams:=LMethod.GetParameters;
     if Length(Args)=Length(LParams) then
     begin
       Found:=True;
       for LIndex:=0 to Length(LParams)-1 do
       if LParams[LIndex].ParamType.Handle<>Args[LIndex].TypeInfo then
       begin
         Found:=False;
         Break;
       end;
     end;

     if Found then Break;
   end;

   if (LMethod<>nil) and Found then
     Result:=LMethod.Invoke(Instance,Args)
   else
     raise Exception.CreateFmt('method %s not found',[MethodName]);
end;

现在,您可以通过以下方式之一调用类的构造函数或方法

r := RttiMethodInvokeEx('Create',t,t.MetaclassType,[444]);
   r := RttiMethodInvokeEx('Create',['hello from constructor string']);
   r := RttiMethodInvokeEx('Create',[]);
   RttiMethodInvokeEx('Bar',r.AsObject,['this is a string']);
   RttiMethodInvokeEx('Bar',[9999]);

(编辑:李大同)

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

    推荐文章
      热点阅读