【问题标题】:Casting TList<T:class> to TList<W:class>将 TList<T:class> 转换为 TList<W:class>
【发布时间】:2014-02-10 12:20:03
【问题描述】:

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

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

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

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

【问题讨论】:

  • 这可以正常工作,但有点粗略。我怀疑无论如何你都需要在这里使用演员表。您可以通过 RTTI 联系​​到枚举器。
  • 由于TForm 派生自TObject 并且TList&lt;TSomeThing&gt; 是类型化指针的通用列表,因此您的操作没有任何问题。也就是说,使用基类中的方法。
  • @LURD 我认为这是不对的。 TList&lt;TObject&gt; 不是 TList&lt;TForm&gt; 的基类。您会发现TList&lt;TForm&gt; is TList&lt;TObject&gt; 的计算结果为False。公共基础是TList&lt;T&gt;。另一种思考方式。如果它只是使用基类中的方法,为什么需要强制转换?
  • @LURD 对不起,我在那条评论中弄错了代码。当然,is 在这里不好,因为它们都是类。我的意思是TList&lt;TForm&gt;.InheritsFrom(TList&lt;TObject&gt;)
  • @DavidHeffernan,我主要指的是基类TFormvs TObject。我希望TList&lt;TForm&gt; 的行为方式与TList&lt;TObject&gt; 相似,而对于任何TList&lt;T&gt; 都不是这样。

标签: delphi casting rtti generic-collections tlist


【解决方案1】:

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

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

是假的。所以TList&lt;TForm&gt; 对象不是TList&lt;TObject&gt;。如果是这样,那么演员就不需要了。

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

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

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

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

【讨论】:

  • 谢谢@David-Heffernan!我的目标是使用 RTTI 枚举 Form 的孩子。枚举器返回 TEnumerator 但我不想在我的单元中包含 FMX.Types。所以我想将结果转换为 TEnumerator 之类的东西,这会引发上述问题。
  • 您需要 not 来强制转换为具体类型。您需要完全沉浸在 RTTI 的世界中。你的代码可以工作,但它依赖于实现细节。
  • “你需要完全沉浸在 RTTI 的世界里”——好点 :)
  • 顺便说一句,我的简单(并且可能是错误的)逻辑是:如果 W & T 是类的实例,那么您可以将它们强制转换为一个共同的祖先,即 TObject 假设您确定它们是类实例。
  • WT 有一个共同的祖先。但这不是我们正在处理的问题。这是TList&lt;W&gt;TList&lt;T&gt;,我们进入了通用不变性。我对我链接到的问题的回答以及那里的链接值得一读。也许我在帮助您理解通用方差方面会比我在那个问题上的提问者更成功! ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
相关资源
最近更新 更多