मैं निम्नलिखित इंटरफेस और एक वर्ग है कि उन्हें लागू करता है - '! बुरा'डेल्फी में, आप कैसे जांच सकते हैं कि एक IInterface संदर्भ एक व्युत्पन्न लेकिन स्पष्ट रूप से समर्थित इंटरफ़ेस लागू नहीं करता है?
IBase = Interface ['{82F1F81A-A408-448B-A194-DCED9A7E4FF7}']
End;
IDerived = Interface(IBase) ['{A0313EBE-C50D-4857-B324-8C0670C8252A}']
End;
TImplementation = Class(TInterfacedObject, IDerived)
End;
निम्नलिखित कोड प्रिंट -
Procedure Test;
Var
A : IDerived;
Begin
A := TImplementation.Create As IDerived;
If Supports (A, IBase) Then
WriteLn ('Good!')
Else
WriteLn ('Bad!');
End;
यह थोड़ा कष्टप्रद लेकिन समझ में आता है। समर्थन आईबीएएस में नहीं डाला जा सकता है क्योंकि आईबीएएस जीआईआईडी की सूची में नहीं है जो टीआईपीमेंटेशन का समर्थन करता है।
TImplementation = Class(TInterfacedObject, IDerived, IBase)
अभी तक कर कि मैं पहले से ही पता कि एक को लागू करता घोषित क्योंकि एक एक IDerived है और एक IDerived एक घोषित है बिना - यह करने के लिए घोषणा बदलते द्वारा निर्धारित किया जा सकता है। तो अगर मैं चेक बाहर छोड़ मैं एक डाल सकता है और सब कुछ ठीक हो जाएगा -
Procedure Test;
Var
A : IDerived;
B : IBase;
Begin
A := TImplementation.Create As IDerived;
B := IBase(A);
//Can now successfully call any of B's methods
End;
लेकिन हम एक समस्या का सामना करना है जब हम एक सामान्य कंटेनर में IBases डालना आरंभ - उदाहरण के लिए TInterfaceList। यह केवल IInterfaces पकड़ सकता है तो हमें कुछ कास्टिंग करना है।
Procedure Test2;
Var
A : IDerived;
B : IBase;
List : TInterfaceList;
Begin
A := TImplementation.Create As IDerived;
B := IBase(A);
List := TInterfaceList.Create;
List.Add(IInterface(B));
Assert (Supports (List[0], IBase)); //This assertion fails
IBase(List[0]).DoWhatever; //Assuming I declared DoWhatever in IBase, this works fine, but it is not type-safe
List.Free;
End;
मैं बहुत ज्यादा किसी भी बेमेल प्रकार को पकड़ने के लिए दावे के कुछ प्रकार करना चाहते हैं - बात की इस तरह Is ऑपरेटर का उपयोग की वस्तुओं के साथ किया जा सकता है, लेकिन वह इंटरफेस के लिए काम नहीं करता। विभिन्न कारणों से, मैं समर्थित इंटरफ़ेस की सूची में स्पष्ट रूप से आईबीएएस नहीं जोड़ना चाहता हूं। क्या कोई तरीका है कि मैं टीआईमिमेंटेशन और इस तरह से दावा लिख सकता हूं कि यह सही iff हार्ड-कास्टिंग आईबीएएस (सूची [0]) का मूल्यांकन करेगा एक सुरक्षित बात है?
संपादित करें:
के रूप में यह जवाब, मैं दो प्रमुख कारण जोड़ रहा मैं इंटरफ़ेस TImplementation लागू करता है की सूची में घोषित जोड़ने के लिए नहीं करना चाहते हैं में से एक में आया।
सबसे पहले, यह वास्तव में समस्या को हल नहीं करता है। , तो Test2, अभिव्यक्ति में:
Supports (List[0], IBase)
रिटर्न सच, इसका मतलब यह नहीं है कि यह एक कठिन डाली प्रदर्शन करने के लिए सुरक्षित है। अनुरोध इंटरफ़ेस को संतुष्ट करने के लिए QueryInterface एक अलग पॉइंटर लौटा सकता है। उदाहरण के लिए, यदि TImplementation स्पष्ट रूप से लागू करता है दोनों घोषित और IDerived (और IInterface), तो दावे को सफलतापूर्वक पारित करेंगे:
Assert (Supports (List[0], IBase)); //Passes, List[0] does implement IBase
लेकिन कल्पना किसी ने गलती से किसी IInterface
List.Add(Item As IInterface);
के रूप में सूची में कोई आइटम जोड़ता है कि
दावा अभी भी गुजरता है - आइटम अभी भी आईबीएएस लागू करता है, लेकिन सूची में जोड़ा गया संदर्भ केवल एक IInterface है - इसे आईबीएएस में हार्ड-कास्टिंग करने से कुछ भी समझदार नहीं होगा, इसलिए यह जांचने में पर्याप्त नहीं है कि निम्नलिखित कठोर -कास्ट सुरक्षित है। एक ही तरीका है कि काम करने के लिए गारंटी है एक के रूप में उपयोग करने के लिए डाली है या समर्थन करता होगा:
(List[0] As IBase).DoWhatever;
लेकिन यह एक निराशा प्रदर्शन लागत के रूप में यह कोड को सूची में आइटम जोड़ने की जिम्मेदारी करने का इरादा है है, सुनिश्चित करें कि वे आईबीएएस के प्रकार हैं - हमें यह मानने में सक्षम होना चाहिए (इसलिए यह धारणा झूठ बोलने का दावा है)।यदि कोई भी कुछ प्रकार बदलता है तो बाद में गलतियों को पकड़ने के अलावा, दावा भी आवश्यक नहीं है। मूल समस्या यह समस्या आती है, यह भी काफी महत्वपूर्ण है, इसलिए एक प्रदर्शन लागत जो कम प्राप्त करती है (यह अभी भी रन-टाइम पर केवल विचलित प्रकारों को पकड़ती है, लेकिन बिना किसी तेज रिलीज बिल्ड को संकलित करने की संभावना के बिना) कुछ ऐसा है जो मैं बचाना चाहता हूं ।
दूसरा कारण यह है कि मैं समानता के संदर्भों की तुलना करने में सक्षम होना चाहता हूं, लेकिन ऐसा नहीं किया जा सकता है यदि एक ही कार्यान्वयन वस्तु विभिन्न वीएमटी ऑफ़सेट के साथ विभिन्न संदर्भों द्वारा आयोजित की जाती है।
संपादित करें 2: एक उदाहरण के साथ उपरोक्त संपादन का विस्तार किया।
संपादित करें 3: नोट: प्रश्न यह है कि मैं दावा कैसे बना सकता हूं ताकि कठोर-कास्ट सुरक्षित हो, अगर कथन पास हो जाए, तो हार्ड-कास्ट से कैसे बचें। हार्ड-कास्ट चरण को अलग-अलग करने के तरीके हैं, या इसे पूरी तरह से टालने के लिए, लेकिन यदि रनटाइम प्रदर्शन लागत है, तो मैं उनका उपयोग नहीं कर सकता। मैं दावे के भीतर जांच की सभी लागत चाहता हूं ताकि इसे बाद में संकलित किया जा सके।
यह कहकर कि, अगर कोई समस्या प्रदर्शन से पूरी तरह से समस्या से बच सकता है और कोई प्रकार की जांच खतरे नहीं होगी!
मेरे परीक्षणों में GetInterfaceTable() में वीएमटी ऑफ़सेट बराबर था, भले ही दो अलग-अलग GUID लागू किए गए थे - यह समझ में आता है कि एक इंटरफ़ेस दूसरे से "विरासत" प्राप्त करता है, तो आधार केवल उसी तालिका के पहले भाग को इंगित करता है । – mghie
क्या वह Win32 कोड में था? मैंने पाया कि प्रत्येक इंटरफ़ेस जिसे मैंने स्पष्ट रूप से TImplementation में जोड़ा है, क्लास इंस्टेंस आकार को 4 बाइट्स तक बढ़ाया - एक अतिरिक्त वीएमटी पॉइंटर। विरासत इंटरफेस से भी, प्रत्येक GUID का समर्थन करने के लिए पारित किया गया, एक अद्वितीय पता वापस कर देगा। – David
कारण मैं पूछता हूं कि मुझे लगता है कि .NET डेल्फी अलग-अलग व्यवहार कर सकता है - मैं एक Win32 टैग – David