Pregunta

I have a list of type TList<TForm>. I need to cast it and use it as TList<TObject> like this:

procedure mainForm.testCast;
var
  listT: TList<TForm>;
  listW: TList<TObject>;
  obj: TObject;
begin
  listT := TList<TForm>.create;
  listT.add(form1);
  listT.add(form2);

  listW := TList<TObject>(listT);  // Casting is OK

  // This works, but is this fine?
  for obj in listW do
    memo1.lines.add(obj.className);

end;

The sample works as expected, but is it ok to cast like this between generic lists? Will this cause some data structure corruption etc? I use it only for looping (DoGetEnumerator) purposes and some string checks i.e. I'll not add/remove items.

The real function is little more complicated. It gets reference to listT using RTTI in a TValue. The main goal is not to link FMX.Forms in my unit.

Update: Why are TGeneric<Base> and TGeneric<Descendant> incompatible types?

¿Fue útil?

Solución

Well, your code will work, but it somewhat dubious in my view. Simply put the cast is not legal because

TList<TForm>.InheritsFrom(TList<TObject>)

is false. So a TList<TForm> object is not a TList<TObject>. If it were, then the cast would not be needed.

That this is so is because Delphi's generic types are invariant. More details can be found here: Why is a class implementing an interface not compatible with the interface type when used in generics?

If you have any difficulty understanding why the designers made generic types invariant, consider for a moment the effect of writing listW.Add(TObject.Create) in your code. Think what it means to the true underlying object of type TList<TForm>.

So the language promises you nothing. You are venturing outside its guarantees. It so happens that the implementation of these two un-related types is compatible enough for your code to work. But that is really just an accident of implementation.

Since you are already using RTTI, then I suggest that you iterate over the list with RTTI. You can call GetEnumerator and so on using RTTI. That way you will call the actual methods of the object.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top