문제

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?

도움이 되었습니까?

해결책

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top