2017-03-16 13 views
2

Ich muss eine Klasse durchlaufen, die eine komplexe Struktur mit RTTI hat. Die Klasse hat mehrere Record Member, die ich auch durchlaufen möchte.Delphi - übergeben Sie TValue an die generische Methode

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

Ich weiß, wenn ich ein Mitglied in der Klasse haben, die ein Datensatz ist:

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 

Wie kann ich die TValue als Parameter an DoGetValuesForRecord passieren, so kann ich auch durch den Rekord iterieren?

Antwort

7

die AsType<T> Methode von TValue Verwenden Sie den Wert zu T würfen

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

Dieses einfache Programm zeigt dies:

{$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. 

Natürlich ist dies nicht erforderlich, dass die Eigenschaft prop der ist richtiger Typ. Wenn nicht, werden Sie einen Laufzeitfehler finden. In meinem obigen Beispiel stelle ich sicher, dass dies der Fall ist, indem ich den Namen der Eigenschaft teste, um sicherzustellen, dass ich die gewünschte Eigenschaft erhalte. Wenn Sie diesen Test entfernen, schlägt das Programm mit einer Laufzeit EInvalidCast Fehler fehl.

Mit Blick auf Ihren Code vermute ich, dass Sie solche Fehler ziemlich wahrscheinlich sind. Es wäre für mich überraschend, wenn jede einzelne Eigenschaft von rt vom gleichen Typ wäre.

Mit Blick auf TRTTIHelpers<T> Ich denke nicht, dass es Ihnen in seiner jetzigen Form sehr nützlich sein wird. Zumindest wird es nicht gut mit Code interagieren, der auf RTTI basiert. Der Grund dafür ist, dass Aufrufe an TRTTIHelpers<T> erfordern, dass Sie den Typparameter zur Kompilierzeit angeben. Aber mit RTTI-Code kennen Sie diesen Typ zur Kompilierzeit nicht. Ich vermute, dass TRTTIHelpers<T> wahrscheinlich keine generische Klasse sein sollte, und verwenden Sie stattdessen RTTI-Typen, um Ihnen Funktionalität anzubieten, die für die Laufzeitbestimmte Typisierung flexibel ist. Dieser Rat könnte natürlich falsch sein, aber ich habe nur die kleinen Auszüge des Codes in der Frage, um mich zu führen.

+0

Nun, das ist die Antwort auf die Frage, die Sie gestellt haben. Der Laufzeitfehler sagt Ihnen, dass, was immer in 'lValue' ist, es nicht vom Typ' T' ist. –

+0

Was ist in lValue ist vom Typ TRTTIRecordType - wenn prop.PropertyType ist TRttiRecordType dann - und ich habe in meiner Klasse einen Datensatztyp – RBA

+0

Ja, ein Datensatztyp. Aber nicht unbedingt der gleiche Typ wie das generische 'T', wie der Laufzeitfehler mitteilt. –

Verwandte Themen