2

我有一个 type 列表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) 目的和一些字符串检查,即我不会添加/删除项目。

真正的功能稍微复杂一点。它参考listTTValue. 主要目标是不链接FMX.Forms到我的单位。

更新: 为什么 TGeneric<Base> 和 TGeneric<Descendant> 类型不兼容?

4

1 回答 1

1

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

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

是假的。所以 TList<TForm>对象不是TList<TObject>. 如果是这样,那么演员就不需要了。

之所以如此,是因为 Delphi 的泛型类型是不变的。更多细节可以在这里找到: 为什么在泛型中使用实现接口的类与接口类型不兼容?

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

所以语言对你没有任何承诺。您正在冒险超出其保证范围。碰巧这两种不相关类型的实现足够兼容,可以让您的代码正常工作。但这实际上只是实施的一个意外。

既然您已经在使用 RTTI,那么我建议您使用 RTTI 遍历列表。您可以使用 RTTI 调用GetEnumerator等。这样,您将调用对象的实际方法。

于 2014-02-10T14:33:22.150 回答