2012-03-26 14 views
7

पालन कोड पर विचार करें:क्या कोई जेनेरिक प्रकार है जो QueryInterface लागू करता है?

[DCC Error] test.pas(104): E2003 Undeclared identifier: 'QueryInterface' 

वहाँ एक सामान्य सूची है कि IInterface लागू करता है:

TMyList = class(TList<IMyItem>, IMyList) 

डेल्फी मुझे त्रुटि दिखाता है?

उत्तर

9

Generics.Collections में कक्षाएं IInterface लागू नहीं करती हैं। आपको इसे अपने व्युत्पन्न कक्षाओं में पेश करना होगा और मानक कार्यान्वयन प्रदान करना होगा। या एक अलग, तीसरी पार्टी, कंटेनर कक्षाओं के साथ काम करने के लिए सेट करें।

उदाहरण के लिए:

TMyList = class(TInterfacedList<IMyItem>, IMyList) 

याद रखें कि आप संदर्भ गिना जीवन प्रबंधन का उपयोग करता है किसी भी अन्य की तरह इस वर्ग के इलाज के लिए की जरूरत है:

TInterfacedList<T> = class(TList<T>, IInterface) 
protected 
    FRefCount: Integer; 
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; 
    function _AddRef: Integer; stdcall; 
    function _Release: Integer; stdcall; 
end; 

function TInterfacedList<T>.QueryInterface(const IID: TGUID; out Obj): HResult; 
begin 
    if GetInterface(IID, Obj) then 
    Result := 0 
    else 
    Result := E_NOINTERFACE; 
end; 

function TInterfacedList<T>._AddRef: Integer; 
begin 
    Result := InterlockedIncrement(FRefCount); 
end; 

function TInterfacedList<T>._Release: Integer; 
begin 
    Result := InterlockedDecrement(FRefCount); 
    if Result = 0 then 
    Destroy; 
end; 

तब आप अपने विशेष वर्ग घोषणा कर सकते हैं। केवल इंटरफेस के माध्यम से इसका संदर्भ लें।

TInterfacedList<T> से पहले आप वास्तव में कुछ और काम करना चाहते थे। आपको IList<T> घोषित करने की आवश्यकता होगी जो सूची क्षमताओं का पर्दाफाश करेगी।

IList<T> = interface 
    function Add(const Value: T): Integer; 
    procedure Insert(Index: Integer; const Value: T); 
    .... etc. etc. 
end; 

आप तो बस TInterfacedList<T> द्वारा समर्थित इंटरफेस की सूची और आधार वर्ग TList<T> करने के लिए IList<T> जोड़ सकते हैं इंटरफ़ेस अनुबंध को पूरा होगा: यह कुछ इस तरह होगा।

TInterfacedList<T> = class(TList<T>, IInterface, IList<T>) 
+2

यह TInterfaceObject के तरीकों की नकल करने के लिए सुरक्षित है? –

+0

ठीक है। मैं इसे याद रखने की कोशिश करूंगा! –

+1

मैंने जवाब थोड़ा सा जवाब दिया है। 'TList ' के आधार पर एक सुंदर सक्षम 'IList ' प्राप्त करने के लिए यह बहुत अधिक काम नहीं है। –

3

एलेक्स सियोबानु के Collections पुस्तकालय पर एक नज़र डालें। इसे Generics.Collections प्रकारों के प्रतिस्थापन समेत जेनेरिक संग्रहों का एक गुच्छा मिला है, जो इंटरफेस के रूप में प्रयोग योग्य हैं। (वे उस तरह से LINQ शैली Enex व्यवहार वह की स्थापना की सुविधा के लिए किया गया था।)

+0

मेरी इच्छा है कि मैं 1 से अधिक उत्तर स्वीकार कर सकता हूं। आपके द्वारा प्रदान किए गए महान टूल। +1 –

0

एक अन्य विकल्प एक आवरण है कि TInterfacedObject से विरासत बना सकते हैं और सूची कार्यक्षमता के लिए संरचना और प्रतिनिधिमंडल उपयोग करने के लिए है:

interface 
type 
    IList<T> = interface<IEnumerable<T>) 
    function Add(const Value: T): Integer; 
    .. 
    end; 

TList<T> = class(TInterfacedObject, IList<T>) 
private 
    FList: Generics.Collections.TList<T>; 
public 
    function Add(const Value:T): Integer; 
    .. 
end; 

implementation 
function TList<T>.Add(const Value:T): Integer; 
begin 
    Exit(FList.Add(Value)); 
end; 

रैपिंग TList<T> और TDictionary<T> कोड की 500 से अधिक लाइनें लेती है।

एक चेतावनी ... मैं इसे यहाँ शामिल नहीं किया था, लेकिन मैं (संबंधित IEnumerator<T> के रूप में भी) एक IEnumerable<T> बनाया नहींIEnumerable से उतर करता है। अधिकांश तीसरे पक्ष और ओएसएस संग्रह पुस्तकालय वही करते हैं। यदि आप रुचि रखते हैं कि क्यों this ब्लॉगपोस्ट काफी अधिक है।

अच्छा, वास्तव में यह सबकुछ का उल्लेख नहीं करता है। भले ही आप एक-दूसरे पर चलने वाले इंटरफेस के आसपास काम करते हैं, फिर भी आपको समस्याएं मिलेंगी। एक अन्यथा सही कार्यान्वयन जो दोनों इंटरफ़ेस को संतुष्ट करता है, यदि आप बिल्ड करते हैं तो सफल हो जाएंगे, लेकिन यदि आप एक वृद्धिशील संकलन (कम से कम डी 200 9 में) करते हैं तो उसी त्रुटि संदेश में असफल रहना जारी रखें। इसके अलावा nongeneric IENumerator आपको वर्तमान आइटम को TObject के रूप में वापस करने के लिए मजबूर करता है। यह बहुत कुछ आपको संग्रह में कुछ भी रखने से रोकता है जिसे TObject पर नहीं डाला जा सकता है।यही कारण है कि मानक सामान्य संग्रह में से कोई भी लागू IEnumerable<T>

+0

इस तरह से TList से प्राप्त करने से अधिक काम करता है। –

+0

तो स्क्रैच से अपना खुद का कार्यान्वयन करता है, जो कि उन सभी तृतीय पक्ष संग्रह करता है। यह सब आपके लिए आवश्यक चीज़ों पर निर्भर करता है। यदि आपको सूची अर्थशास्त्र के साथ एक संदर्भ गणना संग्रह की आवश्यकता है, लेकिन आप सीमित करना चाहते हैं कि कैसे कॉलर संग्रह के साथ बातचीत कर सकता है, 'TList ' लपेटना बेहतर हो सकता है। मैंने कभी नहीं कहा कि यह एक बेहतर समाधान था, बस एक विकल्प। –

4

यहाँ कुछ स्पष्टीकरण ऊपर मेरी टिप्पणी के अलावा क्यों डेल्फी में जेनेरिक इंटरफेस guids साथ काम नहीं करते है।

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 


type 
    IList<T> = interface 
    ['{41FA0759-9BE4-49D7-B3DD-162CAA39CEC9}'] 
    end; 

    IList_String1 = IList<string>; 

    IList_String2 = interface(IList<string>) 
    ['{FE0CB7A6-FC63-4748-B436-36C07D501B7B}'] 
    end; 

    TList<T> = class(TInterfacedObject, IList<T>) 
    end; 

var 
    list: TList<string>; 
    guid: TGUID; 
begin 
    list := TList<string>.Create; 

    guid := IList<Integer>; 
    Writeln('IList<Integer> = ', guid.ToString); 
    if Supports(list, IList<Integer>) then 
    Writeln('FAIL #1'); 

    guid := IList_String1; 
    Writeln('IList_String1 = ', guid.ToString); 
    if not Supports(list, IList_String1) then 
    Writeln('FAIL #2'); 

    guid := IList_String2; 
    Writeln('IList_String2 = ', guid.ToString); 
    if not Supports(list, IList_String2) then 
    Writeln('FAIL #3'); 

    Readln; 
end. 

आपको लगता है कि इसे बाहर IList के लिए एक ही GUID और IList_String1 के लिए के रूप में IList इस GUID मिला लिखते हैं देख सकते हैं और दोनों इस प्रकार से हैं। इसका परिणाम विफल # 1 में होता है क्योंकि समर्थन कॉल करते समय टी कोई फर्क नहीं पड़ता। IList कार्यों के लिए उपनाम परिभाषित करना (कोई विफल # 2) लेकिन मदद नहीं करता है क्योंकि यह अभी भी वही मार्गदर्शक है। इसलिए हमें जो चाहिए वह IList_String2 के साथ किया गया है। लेकिन वह इंटरफ़ेस TList द्वारा लागू नहीं है, इसलिए निश्चित रूप से हमें विफल # 3 मिलती है।

यह बहुत पहले सूचित किया गया है: http://qc.embarcadero.com/wc/qcmain.aspx?d=78458

+0

क्या इस से बचने वाले GUIDs का समर्थन करने और समर्थन करने का कोई तरीका है? –

+0

यह निर्भर करता है। वसंत में हमने जेनेरिक इंटरफेस पर गिट्स डालने का फैसला नहीं किया, लेकिन संग्रह से संबंधित इंटरफेस (जैसे IList ) में एक गैर सामान्य इंटरफेस है जो टीवीएयू के साथ काम करता है। इसके अलावा आईनेमेरेबल (जो अन्य सभी संग्रह संबंधित इंटरफेस का मूल प्रकार है) में एलीमेंटटाइप नामक एक संपत्ति है जो आपको टी –

+0

@StefanGlienke का टाइपइन्फो देता है मैंने वसंत के बारे में सुना है और मैं सोच रहा था कि आप किस प्रकार के ढांचे पर वस्तुओं का मज़ाक उड़ाते हैं आपके यूनिट परीक्षण। मुझे डेल्फी के लिए एक अच्छा नकली ढांचा नहीं मिला है। –

संबंधित मुद्दे

 संबंधित मुद्दे