TRttiMethod.Invoke函数在重载方法中不起作用? [英] TRttiMethod.Invoke function doesn't work in overloaded methods?

查看:368
本文介绍了TRttiMethod.Invoke函数在重载方法中不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 TRttiMethod.Invoke创建课程实例函数,但是当构造函数或方法重载时,rtti不会调用正确的方法。

I'm creating an instance of a class using the TRttiMethod.Invoke function , but when the constructor or a method is overloaded, the rtti does not call the proper method.

我写了一个示例应用程序来解决我的问题。

I wrote a sample app to ilustate my problem.

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调用类的重载方法的另一种方法?

This is a RTTI bug? or exist another way to call the overloaded methods of a class using the RTTI?

推荐答案

TRttiMethod.Invoke 方法,您的问题位于 GetMethod 。此函数内部调用 TRttiType.GetMethods ,并检索一个指向与传递为参数的名称匹配的第一个方法的指针。所以当你执行这个代码 t.GetMethod('Create')你总是得到一个指向同一个方法的指针。

There is nothing wrong with the TRttiMethod.Invoke method, your issue is located in the GetMethod. This function internally call to the TRttiType.GetMethods and retrieves a pointer to the first method which match with the name passed as parameter. So when you are executing this code t.GetMethod('Create') you always are getting a pointer to the same method.

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

To execute an overloaded version of the constructor or another method you must resolve the method address to execute based in the parameters, and then call the TRttiMethod.Invoke function.

检查此示例函数。

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;

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

Now you can call the constructors or methods of your class in one of these ways

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

这篇关于TRttiMethod.Invoke函数在重载方法中不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆