2017-03-16 3 views
2

RTTIを使用して複雑な構造を持つクラスを反復処理する必要があります。クラスには、繰り返したいいくつかのレコードメンバーがあります。Delphi - TValueから汎用メソッドへ

TRTTIHelpers<T> = class 
    public 
    class function DoGetValuesForClass(aClassInst: T): TStringList; 
    class function DoGetValuesForRecord(aRec: T): TStringList; 
    end; 

私は記録であるクラスのメンバを持っているとき、私は知っている:私も、レコードを反復処理できるよう

for prop in rt.GetProperties() do 
    begin 
     if prop.PropertyType is TRttiRecordType then 
     begin 
     lValue := prop.GetValue(aInst); 
     Result.AddStrings(TRTTIHelpers<T>.DoGetValuesForRecord(TValue)); <-- 
     end 

にはどうすれDoGetValuesForRecordにパラメータとしてTValueを渡すことができますか?

答えて

7

Tに値をキャストするTValueAsType<T>メソッドを使用します。

lValue := prop.GetValue(aInst); 
Result.AddStrings(TRTTIHelpers<T>.DoGetValuesForRecord(lValue.AsType<T>)); 

この単純なプログラムは、このことを示しています。もちろん

{$APPTYPE CONSOLE} 

uses 
    System.RTTI; 

type 
    TMyRecord = record 
    foo: Integer; 
    end; 

    TMyClass = class 
    function GetRec: TMyRecord; 
    property Rec: TMyRecord read GetRec; 
    function GetInt: Integer; 
    property Int: Integer read GetInt; 
    end; 

function TMyClass.GetRec: TMyRecord; 
begin 
    Result.foo := 42; 
end; 

function TMyClass.GetInt: Integer; 
begin 
    Result := 666; 
end; 

procedure Main; 
var 
    inst: TMyClass; 
    ctx: TRttiContext; 
    typ: TRttiType; 
    prop: TRttiProperty; 
    value: TValue; 
    rec: TMyRecord; 
begin 
    inst := TMyClass.Create; 
    typ := ctx.GetType(TypeInfo(TMyClass)); 
    for prop in typ.GetProperties do begin 
    if prop.Name='Rec' then begin 
     value := prop.GetValue(inst); 
     rec := value.AsType<TMyRecord>; 
     Writeln(rec.foo); 
    end; 
    end; 
end; 

begin 
    try 
    Main; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    Readln; 
end. 

を、このプロパティpropがであることを必要としません正しいタイプ。そうでなければ、実行時エラーが発生します。上記の例では、プロパティの名前をテストして、目的のプロパティが確実に取得されるようにしています。このテストを削除すると、実行時にプログラムが失敗し、EInvalidCastエラーが発生します。

あなたのコードを見ると、あなたはそのようなエラーに遭遇する可能性が高いと私は思っています。 rtのすべてのプロパティが同じタイプであった場合、私には驚くかもしれません。

TRTTIHelpers<T>私はそれが現在のフォームであなたにとって非常に有用とは思わないと思う。少なくともRTTIに基づいたコードとはうまくやりとりできません。 TRTTIHelpers<T>を呼び出す理由は、コンパイル時に型パラメータを指定する必要があるためです。しかし、RTTIコードでは、コンパイル時にその型を知ることはできません。私はTRTTIHelpers<T>がおそらくジェネリッククラスではないはずで、代わりにRTTI型を使用して、実行時に決定された型付けに対して柔軟な機能を提供すると考えています。もちろん、このアドバイスは間違っているかもしれませんが、私は、私を導く質問には小さなコード抜粋しかありません。

+0

これはあなたが尋ねた質問に対する答えです。実行時エラーは 'lValue'にあるものは' T'型ではないことを伝えています。 –

+0

lValueに含まれるものはTRTTIRecordType型です - prop.PropertyTypeがTRttiRecordTypeの場合 - クラスにレコード型があります – RBA

+0

はい、レコード型です。実行時エラーが通知するので、一般的な 'T'と同じ型である必要はありません。 –

関連する問題