我有一个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?
最佳答案
好的,您的代码可以工作,但是在我看来,这有点可疑。简单地说演员表是不合法的,因为
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
等。这样,您将调用对象的实际方法。关于delphi - 将TList <T:class>转换为TList <W:class>,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21677081/