2012-05-18 12 views
20

में सूची संख्या गणनाकर्ता कार्यान्वित करना मैं एक गणक को लागू करने के लिए डेल्फी एक्सई का उपयोग कर रहा हूं जो सूची के तत्वों को प्रकार के अनुसार फ़िल्टर करने की अनुमति देता है। मैं जल्दी से एक परीक्षण इकाई इकट्ठे इस प्रकार है: D7837: डेल्फी

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. 

इस इकाई संकलन के साथ खतरनाक F2084 आंतरिक त्रुटि विफल रहता है। मैं निश्चित रूप से एक गणक के बिना ऐसा कर सकता हूं, लेकिन कोड को सुसंगत बनाने के लिए मैं एक उपलब्ध हूं। स्प्रिंग 4 डी के शीर्ष पर इसे लागू करने का प्रयास करते समय मेरे पास एक समान संकलक समस्या थी, लेकिन मुझे लगा कि मैं यहां एक सादा, वेनिला डेल्फी मुद्दा डालूंगा।

क्या किसी के पास वैकल्पिक कार्यान्वयन है जो वास्तव में संकलित करता है?

धन्यवाद।

+4

XE2 में एक ही। क्यूसी में जमा करें। जेनरिक अभी भी बहुत ज्यादा उपयोग करने योग्य नहीं हैं। –

+1

बस क्यूसी - # 105719 को सबमिट किया गया। धन्यवाद। –

+1

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

उत्तर

31

आप System.pas से IENumerator < टी > का उपयोग नहीं करना चाहते हैं, मेरा विश्वास करो। यह बात इतनी परेशानी के साथ लाती है क्योंकि यह आईन्यूमेरेटर से प्राप्त होती है और इसलिए अलग-अलग परिणामों के साथ गेटक्रेंट विधि (आईन्यूमेरेटर के लिए टॉब्जेक्ट और आईएन्यूमेरेटर < टी > के लिए टी) है।

बेहतर परिभाषित अपनी खुद की IEnumerator < टी >:

IEnumerator<T> = interface 
    function GetCurrent: T; 
    function MoveNext: Boolean; 
    procedure Reset; 
    property Current: T read GetCurrent; 
end; 

IEnumerable के साथ भी यही। मैं कहूंगा कि अपनी खुद की IEnumerable < टी > को परिभाषित:

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

आप अपने TOfTypeEnumerator < टी, TFilter > में आप बर्फ के कारण विधि संकल्प खंड निकाल सकते हैं कि का उपयोग करते हैं।

जब आप ऐसा करते हैं तो आप अन्य कंपाइलर त्रुटियों E2008, E2089 और कुछ और देखना शुरू कर देंगे।

  • सिर्फ अपने निर्माता में विरासत में मिला करके अपने पूर्वज कक्षा में एक ही हस्ताक्षर जो मौजूद नहीं है के साथ निर्माता कॉल करने के लिए कोशिश करता है। तो इसे विरासत में बदलें में बदलें।

  • IEnumerable का उपयोग नहीं करते लेकिन IEnumerable <TFilter> उपयोग करें, क्योंकि आपके अभाव प्रगणक को क्या

    से अधिक
  • तरीकों और डाले कि केवल वस्तुओं के लिए अनुमति दी जाती है का उपयोग नहीं करते या टी पर वर्ग बाधा निर्दिष्ट है कि और TFilter

  • MoveNext एक परिणाम

की जरूरत है यहाँ संकलन इकाई है। एक त्वरित परीक्षण किया था और यह काम करने लगता है:

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

अच्छी तरह से कहा। दुर्भाग्य से मुझे आपकी सलाह बहुत देर हो गई; सिस्टम इकाई में इंटरफेस लागू करने के लिए एक असली दर्द है! – AdrianGW

1

एक 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. 

का उपयोग कर संस्करण में काम किया एक परीक्षण प्रक्रिया:

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;