2009-06-30 8 views
2

T>の要素のみを含む汎用TObjectList < T>を含む汎用クラスを作成しようとしています。TGenericClass <T> TObjectListを含む<T>はコンパイルされません

uses 
    Generics.Collections; 

type 
    TItem = class 
    end; 

    TGenericClass<T: TItem> = class 
    public 
    SimpleList: TList<T>; // This compiles 
    ObjectList: TObjectList<T>; // This doesn't compile: Compiler complaints that "T is not a class type" 
    end; 

これは間違った構文ですか? BTW:TGenericClass < T:class>がコンパイルされますが、リスト内の項目はTitemではなくなりました。これは私が望ましくないものです。

答えて

6

これはD2009コンパイラを使用したknown bugです。 2009年のアップデート版や修正版、またはDelphi 2010(ウィーバー版)がリリースされると、すぐに修正される可能性が高くなります。それまでは、残念ながらいくつかの回避策が必要です。 :(

7

ジェネリック型は、いくつかの制約を持つことができます。

  • クラス名は、ジェネリック型がクラスの子孫のそのクラスでなければなりません。
  • インターフェイス名は、ジェネリック型でそのインターフェイスを実装する必要があります。
  • 'class'の場合​​、ジェネリック型はクラスでなければなりません(これはクラス名と組み合わせることはできません)。
  • 'レコード'の場合、汎用タイプはレコードでなければなりません。
  • 'constructor'、少し曖昧ですが、汎用クラス型のインスタンスを作成できます。

他のジェネリックを使用するジェネリックを作成する場合は、その制約をコピーする必要があります。それ以外の場合は動作しません。あなたの場合、TObjectListにはクラス制約があります。つまり、あなたのTにもその制約が必要です。

残念ながら、これは名前付きクラス制約と組み合わせることはできません。

は、だから私はあなたがインターフェイスを使用するようにアドバイス、これらを組み合わせることができます

type 
    IItem = interface end; 
    TItem = class (TInterfacedObject, IItem) end; 
    TGenericClass<T: class, IItem> = class 
    private 
    FSimpleList: TList<T>; 
    FObjectList: TObjectList<T>; 
    end; 

以外にも、あなたは誰もがそれらを変更することができ、他のあなたのフィールドをプライベートにする必要があります。

3

私はクラス制約の説明については、(それに+1を与えた)GameCatの答えが好き。

私は働くあなたのコードの若干の修正を持っている。あなたは、Tがなければならないことを言うために制約を与えたので、ということに注意してください。 TItemの子孫をも、あなたは実際にちょうどTObjectList<TItem>としてObjectListを宣言することはできません - ここにTを使用する必要が

を別の方法として、あなたは一種のプロキシを作成することができますまず、フィールドがプライベートであることについてGameCatさんのコメントに注意してください

type 
    TGenericClass<T: TItem> = class 
    private 
    type 
     D = class(TItem); // Proxy to get your T into and object list 
    private 
    SimpleList: TList<T>; 
    ObjectList: TObjectList<D>; // Compiles now, but there is that type issue 
    public 
    procedure Add(Item: T); // No direct access to ObjectList 
    end; 
。。。

オブジェクトリストにアクセスする方法の例は、です。結局のところ、あなたは全く支障なくObjectList.Addにアイテムを渡すことができます。

procedure TGenericClass<T>.Add(Item: T); 
var 
    Obj: TObject; 
begin 
    Obj := Item; 
    ObjectList.Add(D(Obj)); 
end; 

procedure TGenericClass<T>.Add(Item: T); 
begin 
    ObjectList.Add(Item); 
end; 

私はとてもそれが固定取得から身を守るために、しかし、バグかもしれないと思いますあなたのシナリオを考えると、TObjectListはうまくいくはずです。

+0

ええ、これはうまくいくでしょうが、まさに、ジェネリックリストが私たちを解放するために導入された醜いコードのようなものです。これは純粋でシンプルなコンパイラのバグです。それはチームによって認められており、間もなく修正される予定です。このような回避策は現時点では機能しますが、あまりにもそれに慣れないでください。 –

+0

はい、同意します。コンパイラのバグはStebiが自分のコードを修正した後でしか修正されない可能性があります:-)また、ObjectList宣言の型としてTItemを渡すことをお勧めします。私が考えることができる欠点。 –

+0

あなたが正しいのですが、私がオブジェクトリストを一般に公開することを避ければ、すべてが解決可能です。しかし、私は通常のオブジェクトリストを使用してアイテムを希望のタイプTにキャストするだけで十分でしょう。キャストは簡単ではありませんが(コンパイラビッグもそうですが)、ここのように解決できます:http://stackoverflow.com/questions/ 580108/delphi-generic-constraints-problem –

関連する問題