Delphi Rtti:如何从TObjectList<T>中获取对象

3

我正在开发一个自定义的类到XML转换器,其中一个要求是能够流式传输TObjectList<T>字段。
我试图调用ToArray()方法来获取TObjectlist的对象,但由于类型显然不匹配,所以我得到了“无效的类类型转换”错误。

以这个类为例:

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

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

我只需要从Sites TObjectList 中获取Site Objects。 请记住我正在使用RTTI,所以我不知道TObjectList中的ObjectType,因此强制类型转换是行不通的。这是我目前的代码,但似乎走到了死胡同(Obj在这里是TobjectList ):
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;

任何通过RTTI从TObjectList获取对象的方法都对我有好处。由于某些奇怪的原因,我在TypInfo中没有看到GetItem/SetItem方法。
编辑
感谢David,我找到了解决方案:
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;

我可以给出建议,也许有更加“聪明”的方法来实现这个目标...


为什么需要将项目放入数组中?难道不能只调用GetItem逐个读取每个项目吗?您可以将结果存储在TObject中,而无需了解T - Rob Kennedy
@RobKennedy,我在迭代typeinfo.GetMethods()时找不到该方法的原因。 - whosrdaddy
1个回答

4

你的代码失败是因为动态数组不是TObject。

你可以像这样做:

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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接