8

我为我的应用程序编写了一种脚本语言,我的目标是使从 delphi 中发布任何类型的脚本成为可能。我使用 rtti 来自动化这个任务。对于像类这样的任何实例类型,我使用以下代码从脚本中查找和调​​用方法。

var  Info : TRttiType;  
     Meth : TRttiMethod;  
     Param : TArray<TValue>;  
     Result : TValue;  
     AnyClass : TClass;   
begin  
  ...  
  Info := RttiContext.GetType(AnyClass);  
  Meth := Info.GetMethod('AMethod');  
  Setlength(Param, 1);  
  Param[0] := TValue.From<Integer>(11);  
  Result := Meth.Invoke(ClassInstance, Param);  
  ...  
end;  

但是对于记录,此代码不起作用,因为 TRttiMethod 类型不为记录类型提供 Invoke() 方法。我可以通过 Info.GetMethod('AMethod') 从记录类型访问方法信息。
例如我有这样的记录:

TRecordType = record  
  Field1, Field2 : single;  
  procedure Calc(Value : integer);   
end;  

那么如果我有方法名或方法地址,有人知道从记录中调用方法的方法吗?

4

1 回答 1

12

在浏览了上面评论中发布的 delphi 文档中的链接之后,我仔细查看了 System.Rtti 中的 delphi 类型 TRttiRecordMethod。它提供了 DispatchInvoke() 方法,并且该方法需要一个指针。所以下面的代码有效:

TRecordType = record   
  Field1, Field2 : single;   
  procedure Calc(Value : integer);    
end; 


  Meth : TRttiMethod; 
  Para : TRttiParameter; 
  Param : TArray<TValue>; 
  ARec : TRecordType; 
begin 
  Info := RttiContext.GetType(TypeInfo(TRecordType)); 
  Meth := Info.GetMethod('Calc'); 
  Setlength(Param, 1); 
  Param[0] := TValue.From<Integer>(12); 
  Meth.Invoke(TValue.From<Pointer>(@ARec), Param); 
end; 

如果要调用静态方法或重载运算符,则代码不起作用。Delphi 在内部总是将 self 指针添加到参数列表,但这会导致访问冲突。因此,请改用此代码:

  Meth : TRttiMethod; 
  Para : TRttiParameter; 
  Param : TArray<TValue>; 
  ARec : TRecordType; 
begin 
  Info := RttiContext.GetType(TypeInfo(TRecordType)); 
  Meth := Info.GetMethod('&op_Addition'); 
  ... 
  Meth.Invoke(TValue.From<Pointer>(@ARec), Param); 
  Result := System.Rtti.Invoke(Meth.CodeAddress, Param, Meth.CallingConvention, Meth.ReturnType.Handle, Meth.IsStatic); 
end;    
于 2012-04-17T16:02:11.547 回答