将TList <t:class>转换为TList <w:class> </w:class> </t:class>

时间:2014-02-10 12:20:04

标签: delphi casting rtti generic-collections tlist

我有一个TList<TForm>类型的列表。我需要将其转换为TList<TObject>,如下所示:

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;

示例按预期工作,但是可以在通用列表之间进行这样的转换吗?这会导致一些数据结构损坏等吗? 我只将它用于循环(DoGetEnumerator)目的和一些字符串检查,即我不会添加/删除项目。

真正的功能稍微复杂一些。它使用listT中的RTTI引用TValue。 主要目标是不在我的单位中链接FMX.Forms

更新 Why are TGeneric<Base> and TGeneric<Descendant> incompatible types?

1 个答案:

答案 0 :(得分:1)

嗯,你的代码会起作用,但在我看来有点可疑。简单地说演员表是不合法的,因为

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

是假的。因此TList<TForm>对象不是TList<TObject>。如果是,则不需要演员。

这是因为Delphi的泛型类型是不变的。更多详情可在这找到: Why is a class implementing an interface not compatible with the interface type when used in generics?

如果您在理解为什么设计师使泛型类型不变时有任何困难,请考虑一下在代码中编写listW.Add(TObject.Create)的效果。想一想TList<TForm>类型的真正底层对象意味着什么。

所以语言不会让你失望。你在冒险之外冒险。碰巧这两种不相关类型的实现足够兼容,使您的代码能够正常工作。但这实际上只是一次意外事故。

由于您已经在使用RTTI,我建议您使用RTTI迭代列表。您可以使用RTTI调用GetEnumerator等。这样你就可以调用对象的实际方法。