2009-11-06 9 views
11

मैं डेल्फी 2010 में जेनरिक का उपयोग शुरू कर दिया है, लेकिन मैं एक समस्या है जब कोड के इस टुकड़े संकलन है:TGeneric <Base> और TGeneric <Descendant> असंगत प्रकार क्यों हैं?

procedure MakeAllThreadsActive(aThreads: TThreadBaseList<TThreadBase>); 
begin 
... 
end; 

और अंत में मैं कॉल करना चाहते हैं:

TThreadBase = class(TThread) 
... 
end; 

TThreadBaseList<T: TThreadBase> = class(TObjectList<T>) 
... 
end; 

TDataProviderThread = class(TThreadBase) 
... 
end; 

TDataCore = class(TInterfacedObject, IDataCore) 
private 
    FProviders: TThreadBaseList<TDataProviderThread>; 
... 
end; 

तो मैं कुछ नेस्टेड प्रक्रिया है TDataCore वर्ग के कोड में इस नेस्टेड प्रक्रिया:

MakeAllThreadsActive(FProviders); 

लेकिन संकलक यह संकलित करने के लिए नहीं चाहता है और यह कहते हैं ('<> 'कोष्ठक की जगह'() '):

[डीसीसी त्रुटि] LSCore.pas (494): E2010 असंगत प्रकार: ' TThreadBaseList (TThreadBase) 'और ' TThreadBaseList (TDataProviderThread) '

मुझे यह समझ में नहीं आता है हालांकि TDataProviderThread TThreadBase के वंशज है।

MakeAllThreadsActive(TThreadBaseList<TThreadBase>(FProviders)); 

किसी को भी पता है क्यों संकलक इस त्रुटि का कहना है:

मैं कठिन typecasting करके इसे ठीक करने के लिए किया था?

+1

जैसा कि अन्य लोगों ने पहले से ही समझाया है कि आपको यह त्रुटि क्यों मिलती है, MakeAllThreadsActive को TThreadBaseList को कार्य करने के लिए एक विधि बनाने का प्रयास करें। –

उत्तर

22

टीडीटाप्रोवाइडर थ्रेड टीटीएचडबेस का वंशज है, लेकिन TThreadBaseList<TDataProviderThread>TThreadBaseList<TThreadBase> का वंशज नहीं है। यह विरासत नहीं है, इसे कोविरिएन्स कहा जाता है, और हालांकि यह एक ही चीज़ की तरह सहजता से लगता है, यह नहीं है और इसे अलग से समर्थित किया जाना चाहिए। फिलहाल, डेल्फी इसका समर्थन नहीं करता है, हालांकि उम्मीद है कि यह भविष्य में रिलीज होगी।

कॉन्वर्सिस समस्या का मूल कारण यहां दिया गया है: यदि आप जिस फ़ंक्शन को पास करते हैं, वह टीटीएचडबेस ऑब्जेक्ट्स की एक सूची की अपेक्षा कर रहा है, और आप इसे टीडीटाप्रोवाइडर थ्रेड ऑब्जेक्ट्स की एक सूची पास करते हैं, तो इसे कॉल करने से रोकने के लिए कुछ भी नहीं है। कुछ और चिपकाएं अन्य TThreadBase ऑब्जेक्ट उस सूची में है जो TDataProviderTread नहीं है, और अब आपके पास सभी प्रकार की बदसूरत समस्याएं हैं। यह सुनिश्चित करने के लिए आपको कंपाइलर से विशेष चाल की आवश्यकता है कि यह नहीं हो सकता है, अन्यथा आप अपनी प्रकार की सुरक्षा खो देते हैं।

संपादित करें: यहाँ आप के लिए एक संभव समाधान है: एक सामान्य विधि में MakeAllThreadsActive बनाओ, इस तरह:

procedure MakeAllThreadsActive<T: TThreadBase>(aThreads: TThreadBaseList<T>); 

या आप क्या उवे राबी सुझाव कर सकता है। कोई भी काम करेगा।

+2

+1 अच्छा स्पष्टीकरण, भले ही मैं शब्द * covariance * मुख्य रूप से विधियों से जानता हूं। – jpfollenius

+2

यदि आप केवल ऑब्जेक्ट से पढ़ रहे हैं, तो यह ** स्रोत ** है और कॉन्वर्सिस ठीक है।यदि आप इसके बजाय नए मान लिख रहे हैं, तो आपके पास ** सिंक ** है और आप contravariance चाहते हैं। यदि यह एक स्रोत और सिंक दोनों है (जिसे हमें टॉब्जेक्टलिस्ट मानना ​​चाहिए, तो अगर हमारे पास कोई भी तरीका नहीं है तो इसका कोई आंतरिक ज्ञान नहीं है), तो आपके पास कोई भिन्नता नहीं हो सकती है। उस अवधारणा के साथ कंपाइलर को प्रभावित करना "विशेष चाल" से परे चला जाता है। –

+1

जिन विशेष चालों के बारे में मैं बात कर रहा हूं उनमें कंपाइलर को कॉन्वर्सिस और contravariance के लिए समर्थन जोड़ने और फिर TObjectList के व्यक्तिगत तरीकों को चिह्नित करने के लिए कॉन्वर्सिस या contravariance के लिए सुरक्षित के रूप में इस तरह से कॉन्फ़िगर कर सकते हैं कि संकलक इसे सत्यापित कर सकते हैं। –

6

प्रकार

TList <TBase> 

TList <TChild> 

जेनेरिक्स की मूल प्रकार है कि जिस तरह से नहीं किया जा सकता है।

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