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 は内部的に常にセルフ ポインタを parameterlist に追加しますが、これによりアクセス違反が発生します。したがって、代わりに次のコードを使用してください。

  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 に答える