2012-05-18 9 views
20

私はDelphi XEを使用してリストの要素をタイプ別にフィルタリングできる列挙子を実装しています。 D7837:このユニットをコンパイルすると恐ろしいF2084内部エラーで失敗しDelphiのList Enumerator OfType <T>を実装する

unit uTestList; 

interface 

uses Generics.Collections; 

type 
    TListItemBase = class(TObject) 
    end; { TListItemBase } 

    TListItemChild1 = class(TListItemBase) 
    end; 

    TListItemChild2 = class(TListItemBase) 
    end; 

    TTestList<T : TListItemBase> = class; 

    TOfTypeEnumerator<T, TFilter> = class(TInterfacedObject, IEnumerator<TFilter>) 
    private 
    FTestList : TList<T>; 
    FIndex : Integer; 
    protected 
    constructor Create(Owner : TList<T>); overload; 

    function GetCurrent : TFilter; 
    function MoveNext : Boolean; 
    procedure Reset; 

    function IEnumerator<TFilter>.GetCurrent = GetCurrent; 
    function IEnumerator<TFilter>.MoveNext = MoveNext; 
    procedure IEnumerator<TFilter>.Reset = Reset; 
    end; 

    TOfTypeEnumeratorFactory<T, TFilter> = class(TInterfacedObject, IEnumerable) 
    private 
    FTestList : TList<T>; 
    public 
    constructor Create(Owner : TList<T>); overload; 
    function GetEnumerator : TOfTypeEnumerator<T, TFilter>; 
    end; 

    TTestList<T : TListItemBase> = class(TList<T>) 
    public 
    function OfType<TFilter : TListItemBase>() : IEnumerable; 
    end; { TTestList } 


implementation 

{ TOfTypeEnumerator<T, TFilter> } 

constructor TOfTypeEnumerator<T, TFilter>.Create(Owner: TList<T>); 
begin 
    inherited; 
    FTestList := Owner; 
    FIndex := -1; 
end; 

function TOfTypeEnumerator<T, TFilter>.GetCurrent: TFilter; 
begin 
    Result := TFilter(FTestList[FIndex]); 
end; 

function TOfTypeEnumerator<T, TFilter>.MoveNext: Boolean; 
begin 
    Inc(FIndex); 
    while ((FIndex < FTestList.Count) 
     and (not FTestList[FIndex].InheritsFrom(TFilter))) do 
    begin 
    Inc(FIndex); 
    end; { while } 
end; 

{ TOfTypeEnumeratorFactory<T, TFilter> } 

constructor TOfTypeEnumeratorFactory<T, TFilter>.Create(Owner: TList<T>); 
begin 
    inherited; 
    FTestList := Owner; 
end; 

function TOfTypeEnumeratorFactory<T, TFilter>.GetEnumerator: TOfTypeEnumerator<T, TFilter>; 
begin 
    Result := TOfTypeEnumerator<T,TFilter>.Create(FTestList); 
end; 

{ TTestList<T> } 

function TTestList<T>.OfType<TFilter>: IEnumerable; 
begin 
    Result := TOfTypeEnumeratorFactory<T,TFilter>.Create(self); 
end; 

end. 

次のように私はすぐにテストユニットを組み立てています。私は確かに列挙子なしでこれを行うことができますが、私はむしろコードを一貫させるために利用可能なものを持っています。私はこれをSpring4Dの上に実装しようとしたときに同様のコンパイラの問題を抱えていましたが、プレーンなバニラのDelphiの問題をここに入れてしまったと思いました。

誰かが実際にコンパイルする代替実装を持っていますか?

ありがとうございました。

+4

同じ。 QCに送信します。ジェネリック医薬品は依然としてほとんど使用できません。 –

+1

ちょうどQC#105719に提出しました。ありがとう。 –

+1

http://qc.embarcadero.com/wc/qcmain.aspx?d=105719 –

答えて

31

System.pasのIEnumerator <T>を使用したくない場合は、私を信頼してください。それはIEnumeratorから継承され、異なる結果(IEnumeratorの場合はTObject、IEnumeratorの場合はT)<T>のGetCurrentメソッドを継承しているため、大きな問題になります。

より良い自分自身のIEnumerator <T>を定義します。

のIEnumerableと同じ
IEnumerator<T> = interface 
    function GetCurrent: T; 
    function MoveNext: Boolean; 
    procedure Reset; 
    property Current: T read GetCurrent; 
end; 

。私は、あなた自身のIEnumerable <T>を定義すると言うでしょう:

IEnumerable<T> = interface 
    function GetEnumerator: IEnumerator<T>; 
end; 

あなたTOfTypeEnumerator < T、TFilter >にあなたはICEの原因となるメソッド解決節を削除することができますことを使用している場合。

これを行うと、他のコンパイラエラーE2008、E2089などが表示されます。

  • コンストラクタで継承された呼び出しは、存在しない先祖クラスの同じシグネチャでコンストラクタを呼び出そうとします。したがって、継承されたCreateに変更します。それはあなたの希望は、オブジェクトのみに許可されている方法とキャストを使用するか、T上のクラスの制約を指定していない以上

  • 列挙子するものですので、

  • はIEnumerableを使用しますが、IEnumerableを<TFilter>を使用していませんここで

の検索結果を必要とMoveNextメソッドTFilter

  • はコンパイル単位です。簡単なテストを行なったし、動作しているようです:

    unit uTestList; 
    
    interface 
    
    uses 
        Generics.Collections; 
    
    type 
        IEnumerator<T> = interface 
        function GetCurrent: T; 
        function MoveNext: Boolean; 
        property Current: T read GetCurrent; 
        end; 
    
        IEnumerable<T> = interface 
        function GetEnumerator: IEnumerator<T>; 
        end; 
    
        TOfTypeEnumerator<T: class; TFilter: class> = class(TInterfacedObject, IEnumerator<TFilter>) 
        private 
        FTestList: TList<T>; 
        FIndex: Integer; 
        protected 
        constructor Create(Owner: TList<T>); overload; 
    
        function GetCurrent: TFilter; 
        function MoveNext: Boolean; 
        end; 
    
        TOfTypeEnumeratorFactory<T: class; TFilter: class> = class(TInterfacedObject, IEnumerable<TFilter>) 
        private 
        FTestList: TList<T>; 
        public 
        constructor Create(Owner: TList<T>); overload; 
        function GetEnumerator: IEnumerator<TFilter>; 
        end; 
    
        TTestList<T: class> = class(TList<T>) 
        public 
        function OfType<TFilter: class>: IEnumerable<TFilter>; 
        end; 
    
    implementation 
    
    { TOfTypeEnumerator<T, TFilter> } 
    
    constructor TOfTypeEnumerator<T, TFilter>.Create(Owner: TList<T>); 
    begin 
        inherited Create; 
        FTestList := Owner; 
        FIndex := -1; 
    end; 
    
    function TOfTypeEnumerator<T, TFilter>.GetCurrent: TFilter; 
    begin 
        Result := TFilter(TObject(FTestList[FIndex])); 
    end; 
    
    function TOfTypeEnumerator<T, TFilter>.MoveNext: Boolean; 
    begin 
        repeat 
        Inc(FIndex); 
        until (FIndex >= FTestList.Count) or FTestList[FIndex].InheritsFrom(TFilter); 
        Result := FIndex < FTestList.Count; 
    end; 
    
    { TOfTypeEnumeratorFactory<T, TFilter> } 
    
    constructor TOfTypeEnumeratorFactory<T, TFilter>.Create(Owner: TList<T>); 
    begin 
        inherited Create; 
        FTestList := Owner; 
    end; 
    
    function TOfTypeEnumeratorFactory<T, TFilter>.GetEnumerator: IEnumerator<TFilter>; 
    begin 
        Result := TOfTypeEnumerator<T, TFilter>.Create(FTestList); 
    end; 
    
    { TTestList<T> } 
    
    function TTestList<T>.OfType<TFilter>: IEnumerable<TFilter>; 
    begin 
        Result := TOfTypeEnumeratorFactory<T,TFilter>.Create(self); 
    end; 
    
    end. 
    
  • +0

    うまくいった。残念ながらあなたのアドバイスは遅すぎました。 Systemユニットのインターフェースは実装するのに本当の苦痛です! – AdrianGW

    1

    Aはsystem.IEnumerable<T>system.IEnumerator<T>

    unit uTestList; 
    
    interface 
    
    uses Generics.Collections; 
    
    type 
        TListItemBase = class(TObject) 
        end; { TListItemBase } 
    
        TListItemChild1 = class(TListItemBase) 
        end; 
    
        TListItemChild2 = class(TListItemBase) 
        end; 
    
        TTestList<T : TListItemBase> = class; 
    
        TOfTypeEnumerator<T : class; TFilter : class> = class(TInterfacedObject, IEnumerator<TFilter>, IEnumerator) 
        private 
        FTestList : TList<T>; 
        FIndex : Integer; 
        protected 
        constructor Create(Owner : TList<T>); overload; 
    
        function GetCurrent: TObject; 
        function GenericGetCurrent : TFilter; 
        function MoveNext : Boolean; 
        procedure Reset; 
    
        function IEnumerator<TFilter>.GetCurrent = GenericGetCurrent; 
        end; 
    
        TOfTypeEnumeratorFactory<T : class; TFilter : class> = class(TInterfacedObject, IEnumerable<TFilter>, IEnumerable) 
        private 
        FTestList : TList<T>; 
        public 
        constructor Create(Owner : TList<T>); overload; 
        function GetEnumerator : IEnumerator; 
        function GenericGetEnumerator : IEnumerator<TFilter>; 
        function IEnumerable<TFilter>.GetEnumerator = GenericGetEnumerator; 
        end; 
    
        TTestList<T : TListItemBase> = class(TList<T>) 
        public 
        function OfType<TFilter : TListItemBase>() : IEnumerable<TFilter>; 
        end; { TTestList } 
    
    
    implementation 
    
    { TOfTypeEnumerator<T, TFilter> } 
    
    constructor TOfTypeEnumerator<T, TFilter>.Create(Owner: TList<T>); 
    begin 
        inherited Create; 
        FTestList := Owner; 
        FIndex := -1; 
    end; 
    
    function TOfTypeEnumerator<T, TFilter>.GenericGetCurrent: TFilter; 
    begin 
        Result := TFilter(TObject(FTestList[FIndex])); 
    end; 
    
    function TOfTypeEnumerator<T, TFilter>.GetCurrent: TObject; 
    begin 
        Result := TObject(FTestList[FIndex]); 
    end; 
    
    function TOfTypeEnumerator<T, TFilter>.MoveNext: Boolean; 
    begin 
        repeat 
        Inc(FIndex); 
        until (FIndex >= FTestList.Count) or FTestList[FIndex].InheritsFrom(TFilter); 
        Result := FIndex < FTestList.Count; 
    end; 
    
    procedure TOfTypeEnumerator<T, TFilter>.Reset; 
    begin 
        FIndex := -1; 
    end; 
    
    { TOfTypeEnumeratorFactory<T, TFilter> } 
    
    constructor TOfTypeEnumeratorFactory<T, TFilter>.Create(Owner: TList<T>); 
    begin 
        inherited Create; 
        FTestList := Owner; 
    end; 
    
    function TOfTypeEnumeratorFactory<T, TFilter>.GetEnumerator: IEnumerator; 
    begin 
        Result := GenericGetEnumerator; 
    end; 
    
    function TOfTypeEnumeratorFactory<T, TFilter>.GenericGetEnumerator: IEnumerator<TFilter>; 
    begin 
        Result := TOfTypeEnumerator<T,TFilter>.Create(FTestList); 
    end; 
    
    { TTestList<T> } 
    
    function TTestList<T>.OfType<TFilter>: IEnumerable<TFilter>; 
    begin 
        Result := TOfTypeEnumeratorFactory<T,TFilter>.Create(self); 
    end; 
    
    end. 
    

    を使用して、バージョンを働いた試験手順:XE2で

    var 
        MyElem: TListItemBase; 
        MyElem1: TListItemChild1; 
        MyElem2: TListItemChild2; 
    begin 
        Memo1.Clear; 
        for MyElem in FTestList.OfType<TListItemBase>() do 
        begin 
        Memo1.Lines.Add('----------'); 
        end; 
        for MyElem1 in FTestList.OfType<TListItemChild1>() do 
        begin 
        Memo1.Lines.Add('=========='); 
        end; 
        for MyElem2 in FTestList.OfType<TListItemChild2>() do 
        begin 
        Memo1.Lines.Add('++++++++++'); 
        end;