I am working a custom class to xml converter and one of the requirements is the ability to stream TObjectList<T>
fields.
I am trying to invoke the ToArray()
method to get hold of the TObjectlist's objects, but I get 'Invalid class typecast' because the types obviously don't match.
take this class for example:
type
TSite = class
Name : String;
Address : String;
end;
TSites = class
Sites : TObjecList<TSite>;
end;
I just need to get the Site Objects from the Sites TObjectList.
Please keep in mind that I am using RTTI, so I don't know the ObjectType in TObjectList, so Typecasting won't work. This is what I have but it seems a dead end (Obj is TobjectList<TSite>
here):
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;
Any way to get the objects out of the TObjectList via RTTI is good for me. For some odd reason I don't see the GetItem/SetItem methods in TypInfo
EDIT
Thanks to David I have my 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;
I am open for suggestions, maybe there are more 'clever' ways to achieve this goal...
Your code fails because a dynamic array is not a TObject.
You can do it like this:
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;