2013-02-15 12 views
6

जिज्ञासा से बाहर, क्यों संकलक टाइपिंग (ऑब्जेक्ट) से अलग किसी भी अलग तरह से एक अनियंत्रित जेनेरिक प्रकार का इलाज करता है?जेनेरिक और प्रकार की बाधाओं के नियम

class Bar { } 

class Foo 
{ 
    void foo(object thing) 
    { 
     ((Bar)thing).ToString(); 
    } 
} 

class Foo<T> 
{ 
    void foo(T thing) 
    { 
     ((Bar)thing).ToString(); 
    } 
} 

उपर्युक्त में, बार में "टी चीज" कास्टिंग एक संकलक त्रुटि में परिणाम देता है। बार में "ऑब्जेक्ट चीज" कास्टिंग करना हालांकि कुछ ऐसा है जो संकलक मुझे अपने जोखिम पर ही करने देता है।

जो मैं नहीं देखता वह क्यों है। .NET ऑब्जेक्ट में सभी के बाद कैच-सब है और रन-टाइम प्रकार बॉक्स किए गए मान या किसी भी प्रकार का ऑब्जेक्ट हो सकता है। तो मुझे नहीं लगता कि कंपाइलर के लिए दो मामलों के बीच अंतर करने के लिए तर्कसंगत कारण क्या है। सबसे अच्छा मैं ऐसा कर सकता हूं जैसे "प्रोग्रामर संकलक से जेनेरिक प्रकारों के साथ टाइपिंग करने की अपेक्षा करेगा, लेकिन ऑब्जेक्ट के साथ नहीं।" :) क्या यही सबकुछ है इसमें है?

Btw, मैं बस

((Bar)(object)thing).ToString(); 

लिख कर पता है कि मैं अभी भी अपने कलाकारों, फू मामले में किया प्राप्त कर सकते हैं कर रहा हूँ मैं सिर्फ समझने के लिए क्यों संकलक करता चाहते हैं ...

+3

क्या यह आपके लिए 'int' 'बार' डालने के लिए समय कानूनी है? जब आप 'int' के साथ उस प्रकार पैरामीटर को भरते हैं, तो क्या * * * कंपाइलर त्रुटियों को शुरू करना चाहिए? क्या होगा अगर असेंबली तुम्हारा नहीं है, तो आप समस्या नहीं देख सकते हैं? टी वस्तु नहीं है। यह कुछ अविश्वसनीय रूप से विशिष्ट है। –

+1

क्या आप यह भी जानते हैं कि आप 'कक्षा Foo कह सकते हैं जहां टी: बार' से _ensure_ कि' टी' हमेशा 'बार' पर डाला जा सकता है? – Rawling

+1

मुझे यकीन है कि एरिक लिपर्ट के पास इस बारे में एक ब्लॉग पोस्ट है, लेकिन मुझे यह नहीं मिल रहा है ... –

उत्तर

4

यहां महत्व object है। यदि पहला उदाहरण object के अलावा कुछ भी था, तो यह वही व्यवहार करेगा। असल में, क्या तुम यहाँ इस समय कह रहे हैं:

(Bar)thing 

है: "एक Bar करने के लिए एक T कन्वर्ट"; जो सामान्य मामले में कहीं भी कानूनी नहीं है। object जोड़कर आप यह कर:

(Bar)(object)thing 

है जो "एक object करने के लिए एक T परिवर्तित ..." - जो हमेशा कानूनी है, के बाद से object सभी प्रबंधित प्रकार की जड़ है; और ध्यान दें कि यह एक बॉक्स को आमंत्रित कर सकता है - "... और फिर object को Bar के रूप में डालें" - फिर से; यह संकलन समय पर हमेशा कानूनी होता है, और रनटाइम पर एक प्रकार-चेक ("अनबॉक्स-कोई भी") शामिल होता है।

उदाहरण के लिए: मान लीजिए TDateTime है ...

DateTime thing = ... 
Bar bar = (Bar)(object)thing; 

पूरी तरह से वैध है; सुनिश्चित करें कि यह रनटाइम पर असफल हो जाएगा, लेकिन: यह वह परिदृश्य है जिसे आपको ध्यान में रखने की आवश्यकता है।

+0

सही होने पर मुझे लगता है कि ओपी बाद के मामले के लिए * संकलन * समय पर त्रुटि का पर्दाफाश करने के लिए विकल्प के पीछे डिजाइन निर्णय मांग रहा था, लेकिन पूर्व के लिए * रन * समय पर (माना जाता है कि चीज 'बार' में परिवर्तनीय नहीं है। –

+0

आप दोनों (@Marc, @Ron) पर हैं। मुझे लगता है कि यह एक अच्छा स्पष्टीकरण है। किसी चीज को ऑब्जेक्ट कास्टिंग करना हमेशा कुछ कम होता है, लेकिन सामान्य मामला या तो हो सकता है, और इसलिए * निर्मित * प्रकार किसी भी टी के लिए संकलित नहीं होगा - जो एक संकलन-समय त्रुटि देने का एक अच्छा कारण है! –

4

यह जेनेरिक बनाने का अर्थशास्त्र और उद्देश्य नीचे आता है। यदि आपके पास सामान्य प्रकार टी है, तो संकलक आपको मनमाने ढंग से इसे किसी अन्य ऑब्जेक्ट पर सीधे नहीं डालने देगा। यह समझ में आता है क्योंकि टी का उद्देश्य प्रोग्रामर को यह निर्दिष्ट करने के लिए मजबूर करना है कि टी वास्तव में किस प्रकार का है। यह "ऑब्जेक्ट" नहीं होने वाला है, यह ऑब्जेक्ट का एक विशिष्ट प्रकार होगा। संकलन समय पर, संकलक नहीं जानता कि टी में क्या होने जा रहा है और इसलिए इसे कास्ट नहीं किया जा सकता है।

ऑब्जेक्ट से कास्टिंग एक अज्ञात ऑब्जेक्ट के रूप में काम करता है - जैसा कि किसी KNOWN ऑब्जेक्ट प्रकार का विरोध करता है जो उसके उपयोग में परिभाषित हो जाता है।

इसे "कहां" खंड के साथ बढ़ाया जा सकता है। जैसे, आप निर्दिष्ट कर सकते हैं कि टी आईबीआर प्रकार का होना चाहिए;

interface IBar { } 

class Bar : IBar { } 

class Foo<T> 
    where T : IBar 
{ 
    void foo(T thing) 
    { 
     ((IBar)thing).ToString(); 
    } 
} 

विरासत भी खंड के साथ काम करता है;

class Bar { } 

class Foo<T> 
    where T : Bar 
{ 
    void foo(T thing) 
    { 
     // now you don't need to cast at all as the compiler knows 
     // exactly what type T is (at a parent level at least) 
     thing.ToString(); 
    } 
} 
+0

मुझे इसे उत्तर के रूप में चिह्नित करने में प्रसन्नता हो रही है, हालांकि मुझे आपकी मूलभूत जानकारी से थोड़ा अधिक तर्क मिलता है; यह वास्तव में उबालता है "उपयोगकर्ता" की अपेक्षाओं के लिए (मेरे जेनेरिक वर्ग का उपयोगकर्ता, या बल्कि एक निर्मित वर्ग जहां टी परिभाषित किया गया है)। कहने के लिए कि "टी केवल एक वस्तु नहीं है, यह कुछ विशिष्ट है", आईएमएचओ, superflous। कोई भी वस्तु हो सकती है, और आमतौर पर, कुछ बहुत एसपी हो सकता है ecific। और एक ही वस्तु को देखने के विभिन्न तरीके हैं। मैं किसी भी प्रकार का समर्थन करना चाहूंगा, लेकिन किसी विशेष तरीके से व्यवहार कर सकता हूं यदि टाइप एक है जिसे मैं जानता हूं, उदाहरण के लिए - जेनेरिक क्लास या नहीं। –

+0

@TheDag टाइप जे के आधार पर जेनेरिक के व्यवहार को बदलना आम तौर पर एक अच्छा विचार नहीं है हालांकि विशिष्ट प्रकारों को संभालने के लिए वैध मामले हैं, उदाहरण के लिए, बॉक्स किए गए या अनबॉक्स किए गए प्रकार। आपके उदाहरण में, आप सीधे टी से जाने का प्रयास करते हैं जो डिफ़ॉल्ट रूप से लगभग निश्चित रूप से एक विशिष्ट प्रकार के दूसरे विशिष्ट प्रकार 'बार' के रूप में होने जा रहा है। जब कोई रिश्ते या सामान्य इंटरफेस नहीं होता है तो यह '(फू) बार' करने की कोशिश करने के लिए आकर्षक होगा। मुझे अभी भी लगता है कि संकलक चेतावनी वैध है – DiskJunky

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

  • कोई संबंधित समस्या नहीं^_^