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) の目的といくつかの文字列チェックにのみ使用します。つまり、アイテムの追加/削除はしません。

実際の関数はもう少し複雑です。listTでRTTIを使用するための参照を取得しますTValue。主な目標はFMX.Forms、私のユニットにリンクすることではありません。

更新: TGeneric<Base> と TGeneric<Descendant> の型に互換性がないのはなぜですか?

4

1 に答える 1

1

さて、あなたのコードは機能しますが、私の見解ではやや疑わしいです。簡単に言えば、キャストは合法ではありません。

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

は偽です。したがって、 TList<TForm>オブジェクトは ではありませんTList<TObject>。もしそうなら、キャストは必要ありません。

これは、Delphi のジェネリック型が不変であるためです。詳細については、こちらを参照してください: Why is a class implementation an interface not compatible with the interface type when used in generics?

設計者がジェネリック型を不変にした理由を理解するのが難しい場合はlistW.Add(TObject.Create)、コードを記述することの影響を少し考えてみてください。type の真の基礎となるオブジェクトにとってそれが何を意味するかを考えてくださいTList<TForm>

したがって、言語は何も約束しません。あなたはその保証の外に出ています。これら 2 つの無関係な型の実装は、コードが機能するのに十分な互換性がある場合があります。しかし、それは実際には単なる実装の偶然です。

すでに RTTI を使用しているため、RTTI を使用してリストを反復処理することをお勧めします。GetEnumeratorRTTI を使用して通話などを行うことができます。そうすれば、オブジェクトの実際のメソッドを呼び出すことができます。

于 2014-02-10T14:33:22.150 に答える