2015-03-20 10 views
16

इस छोटे से LINQPad उदाहरण लें:क्यों सी # समर्थन संस्करण जेनेरिक वर्ग नहीं है?

void Main() 
{ 
    Foo<object> foo = new Foo<string>(); 
    Console.WriteLine(foo.Get()); 
} 

class Foo<out T> 
{ 
    public T Get() 
    { 
     return default(T); 
    } 
} 

यह इस त्रुटि के साथ संकलित करने के लिए विफल रहता है:

Invalid variance modifier. Only interface and delegate type parameters can be specified as variant.

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

ध्यान में रखते हुए कि इंटरफेस इसका समर्थन करते हैं, तो मुझे उस से तर्कसंगत रूप से अनुसरण करने के लिए वर्ग समर्थन की उम्मीद होगी।

+0

यह सीएलआर सीमा के कारण है। अब यदि आप अपना प्रश्न संशोधित करते हैं तो यह अच्छा होगा ताकि कोई जवाब दे सके कि इस पर सीएलआर सीमा क्यों है। – Stilgar

+4

@Stilgar: क्या आप जवाब नहीं दे सकते "अंतर्निहित सीएलआर कार्यान्वयन में इस बात के कारण यह समर्थित नहीं है"? – Chris

+1

कक्षाओं को कार्यान्वयन के विवरणों के बारे में चिंता करने की आवश्यकता है - प्रतिनिधियों और इंटरफेस नहीं करते हैं।यह काम करना बहुत काम होगा। यह पूछते हुए कि सी # टीम ने इस काम को क्यों नहीं किया, थोड़ा सा व्यर्थ लगता है - उन्होंने नहीं किया, यह समर्थित नहीं है, कहानी का अंत है। –

उत्तर

8

एक कारण यह हो सकता है: क्योंकि यह एक क्षेत्र है

class Foo<out T> 
{ 
    T _store; 
    public T Get() 
    { 
    _store = default(T); 
    return _store; 
    } 
} 

इस वर्ग, एक विशेषता यह है कि covariant नहीं है शामिल है, और क्षेत्रों मूल्यों के लिए सेट किया जा सकता। हालांकि यह एक कॉन्वर्सेंट तरीके से उपयोग किया जाता है, क्योंकि इसे केवल डिफ़ॉल्ट मान दिया जाता है और यह किसी भी मामले के लिए केवल null होने वाला है जहां कॉन्वर्सिस वास्तव में उपयोग किया जाता है।

जैसा कि यह स्पष्ट नहीं है कि हम इसे अनुमति दे सकते हैं। यह उपयोगकर्ताओं को परेशान नहीं करेगा (यह आपके द्वारा सुझाए गए समान संभावित नियमों से मेल खाता है), लेकिन यह मुश्किल है (विश्लेषण पहले से ही थोड़ा मुश्किल हो गया है और हम यह भी नहीं कर रहे हैं कि वास्तव में मुश्किल मामलों की तलाश भी शुरू हो)।

दूसरी ओर, इस बात का विश्लेषण बहुत सरल है:

void Main() 
{ 
    IFoo<object> foo = new Foo<string>(); 
    Console.WriteLine(foo.Get()); 
} 

interface IFoo<out T> 
{ 
    T Get(); 
} 

class Foo<T> : IFoo<T> 
{ 
    T _store; 
    public T Get() 
    { 
    _store = default(T); 
    return _store; 
    } 
} 

यह IFoo<T> टूटता सहप्रसरण के कार्यान्वयन की कि कोई भी निर्धारित करने के लिए आसान है, क्योंकि यह किसी भी नहीं मिला है। यह आवश्यक है कि यह सुनिश्चित करना है कि T का पैरामीटर (एक सेटर विधि सहित) का कोई उपयोग नहीं है और यह हो गया है।

तथ्य यह है कि संभावित प्रतिबंध एक बहुत अधिक इसी तरह के कारणों के लिए एक इंटरफेस पर की तुलना में एक वर्ग पर कठिन है, यह भी डिग्री कम कर देता है जो करने के लिए covariant कक्षाएं उपयोगी होगा। वे निश्चित रूप से बेकार नहीं होंगे, लेकिन यह कितना उपयोगी होगा कि नियमों को निर्दिष्ट करने और उन्हें लागू करने के लिए कितना काम करना होगा, इसके बारे में नियमों को लागू करने के लिए कितना उपयोगी होगा, यह कितना उपयोगी कॉन्वर्स इंटरफेस है यह निर्दिष्ट करने के लिए कि उन्हें निर्दिष्ट और कार्यान्वित करना कितना काम था।

निश्चित रूप से, अंतर के लिए पर्याप्त है कि यह की बात अतीत है "अच्छी तरह से, आप अनुमति देने के लिए एक्स जा रहे हैं यह मूर्खतापूर्ण करने के लिए Y की अनुमति नहीं ... होगा"।

+0

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

+0

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

0

एक कक्षा में केवल आउटपुट विधि पैरामीटर (कॉन्वेंटेंट होने के लिए) और केवल इनपुट विधि पैरामीटर (contravariant होने के लिए) को शामिल करने की आवश्यकता होगी। मुद्दा यह है कि कक्षाओं के लिए यह गारंटी देना मुश्किल है: उदाहरण के लिए, कॉन्वर्सेंट क्लास (टी प्रकार पैरामीटर द्वारा) में टी के फ़ील्ड नहीं हो सकते हैं, क्योंकि आप उन क्षेत्रों में लिख सकते हैं। यह वास्तव में अपरिवर्तनीय वर्गों के लिए बहुत अच्छा काम करेगा, लेकिन इस समय सी # में अपरिवर्तनीयता के लिए कोई व्यापक समर्थन नहीं है (कहें, जैसे स्कैला में)।

+2

यह मेरे उदाहरण के साथ संकलन समय पर आसानी से सत्यापित किया जा सकता है। –

+1

यह गारंटी देना इतना आसान नहीं है कि किसी भाषा में गहरे अपरिवर्तनीय समर्थन के बिना। एक समान प्रश्न पर एरिक लिपर्ट के उत्कृष्ट उत्तर के लिंक देखें (http://stackoverflow.com/questions/2733346/why-isnt-there-generic-variance-for-classes-in-c-sharp-4-0)। – ialekseev

+0

अपरिवर्तनीयता आवश्यक रूप से आवश्यक नहीं है। उदाहरण के लिए, टाइप टी का कोई भी सार्वजनिक क्षेत्र नियमों का उल्लंघन होगा, और टी को अचूक होना होगा। ऐसी कुछ स्थितियां हो सकती हैं जहां भिन्नता लागू होती है, लेकिन वे अभी भी मौजूद हो सकते हैं। –

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