Delphi Rtti: как получить объекты из TObjectList ‹T›

Я работаю над преобразователем пользовательского класса в xml, и одним из требований является возможность потоковой передачи полей TObjectList<T>.
Я пытаюсь вызвать метод ToArray(), чтобы получить объекты TObjectlist, но получаю сообщение «Неверное приведение типа класса», потому что типы явно не совпадают.

возьмем, к примеру, этот класс:

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

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

Мне просто нужно получить объекты сайта из TObjectList сайтов. Имейте в виду, что я использую RTTI, поэтому я не знаю ObjectType в TObjectList, поэтому приведение типов не будет работать. Это то, что у меня есть, но похоже на тупик (здесь Obj TobjectList<TSite>):

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;

Мне подходит любой способ получить объекты из TObjectList через RTTI. По какой-то странной причине я не вижу методов GetItem / SetItem в TypInfo

ИЗМЕНИТЬ

Благодаря Дэвиду у меня есть решение:

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;

Я открыт для предложений, может быть, есть более «умные» способы достичь этой цели ...


person whosrdaddy    schedule 19.09.2012    source источник
comment
Зачем нужно складывать элементы в массив? Не могли бы вы вместо этого просто позвонить GetItem, чтобы читать каждый элемент один за другим? Вы можете сохранить результат в TObject, не зная T.   -  person Rob Kennedy    schedule 19.09.2012
comment
@RobKennedy, я почему-то не нахожу метод при итерации по typeinfo.GetMethods ();   -  person whosrdaddy    schedule 19.09.2012


Ответы (1)


Ваш код не работает, потому что динамический массив не является 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;
person David Heffernan    schedule 19.09.2012