2012-09-19 1 views
3

Je travaille un convertisseur de classe en xml personnalisé et l'une des exigences est la possibilité de diffuser des champs TObjectList<T>.
J'essaye d'invoquer la méthode ToArray() pour obtenir les objets TObjectlist, mais j'obtiens une 'classe incorrecte' parce que les types ne correspondent pas.Delphi Rtti: comment obtenir des objets de TObjectList <T>

prendre cette classe par exemple:

type 
    TSite = class 
    Name : String; 
    Address : String; 
    end; 

    TSites = class 
    Sites : TObjecList<TSite>; 
    end; 

J'ai juste besoin d'obtenir le site Objets du TObjectList Sites. S'il vous plaît gardez à l'esprit que j'utilise RTTI, donc je ne connais pas le ObjectType dans TObjectList, alors Typecasting ne fonctionnera pas. Voilà ce que j'ai, mais il semble une impasse (Obj est TobjectList<TSite> ici):

function TXmlPersister.ObjectListToXml(Obj : TObject; Indent: String): String; 

var 
    TypInfo: TRttiType; 
    meth: TRttiMethod; 
    Arr : TArray<TObject>; 

begin 
Result := ''; 
TypInfo := ctx.GetType(Obj.ClassInfo); 
Meth := TypInfo.GetMethod('ToArray'); 
if Assigned(Meth) then 
    begin 
    Arr := Invoke(Obj, []).AsType<TArray<TObject>>; // invalid class typecast error 

    if Length(Arr) > 0 then 
    begin 
    // get objects from array and stream them 
    ... 
    end; 
    end; 

un moyen d'obtenir les objets de la TObjectList via RTTI est bon pour moi. Pour une raison étrange, je ne vois pas les méthodes GetItem/de SetItem dans TypInfo

EDIT

Merci à David j'ai ma solution:

function TXmlPersister.ObjectListToXml(Obj : TObject; Indent: String): String; 

var 
    TypInfo: TRttiType; 
    meth: TRttiMethod; 
    Value: TValue; 
    Count : Integer; 

begin 
Result := ''; 
TypInfo := ctx.GetType(Obj.ClassInfo); 
Meth := TypInfo.GetMethod('ToArray'); 
if Assigned(Meth) then 
    begin 
    Value := Meth.Invoke(Obj, []); 
    Assert(Value.IsArray); 
    Count := Value.GetArrayLength; 
    while Count > 0 do 
    begin 
    Dec(Count); 
    Result := Result + ObjectToXml(Value.GetArrayElement(Count).AsObject, Indent); 
    end; 
    end; 
end; 

Je suis ouvert aux suggestions, peut-être Il existe d'autres moyens «intelligents» pour atteindre cet objectif ...

+0

Pourquoi avez-vous besoin de mettre les éléments d'un tableau? Ne pourriez-vous pas simplement appeler 'GetItem' à la place pour lire chaque élément un par un? Vous pouvez stocker le résultat dans un 'TObject' sans avoir à connaître' T'. –

+0

@RobKennedy, pour une raison quelconque, je ne trouve pas la méthode lors de l'itération sur typeinfo.GetMethods(); – whosrdaddy

Répondre

4

Votre code échoue car un tableau dynamique n'est pas un TObject.

Vous pouvez le faire comme ceci:

Value := Meth.Invoke(Obj, []); 
Assert(Value.IsArray); 
SetLength(Arr, Value.GetArrayLength); 
for i := 0 to Length(Arr)-1 do 
    Arr[i] := Value.GetArrayElement(i).AsObject; 
Questions connexes