我有一个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?
答案 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
等。这样你就可以调用对象的实际方法。