2009-11-20 6 views
36

सी # संरचना से उत्तराधिकारी संभव नहीं है। यह मेरे लिए स्पष्ट नहीं है कि यह क्यों है:.NET मूल्य प्रकार क्यों सील किए गए हैं?

  • स्पष्ट रूप से आपके पास एक संदर्भ प्रकार नहीं है जो मूल्य प्रकार से प्राप्त होता है; यह
  • एक आदिम प्रकार (Int32, Double, Char, आदि) से प्राप्त करने के लिए उचित नहीं लगता है
  • आपको कॉल (गैर-वर्चुअल) विधियों पर कॉल करने में सक्षम होना चाहिए एक व्युत्पन्न उदाहरण का उपयोग कर आधार। आप एक व्युत्पन्न संरचना से आधार पर जा सकते हैं, क्योंकि वे एक ही स्मृति को ओवरलैप करेंगे। मुझे लगता है कि व्युत्पन्न आधार से कास्टिंग काम नहीं करेगा, क्योंकि आप रनटाइम पर व्युत्पन्न संरचना के प्रकार को नहीं जानते थे।
  • मैं देख सकता है कि आप अपने वर्ग पदानुक्रम में आभासी तरीकों को लागू नहीं कर सकता है, के बाद से मूल्य प्रकार आभासी सदस्यों

मुझे आश्चर्य है कि नहीं हो सकता है अगर यह CLR में एक तकनीकी सीमा, या कुछ है कि है सी # कंपाइलर आपको करने से रोकता है?

संपादित करें: वैल्यू प्रकारों में वर्चुअल विधियां नहीं हो सकती हैं, और मुझे लगता है कि यह सीमाएं उन परिस्थितियों को मानती हैं जिनमें आप विरासत का उपयोग करना चाहते हैं। हालांकि, यह अभी भी विरासत के रूप में एकत्रीकरण छोड़ देता है। फ़ील्ड के साथ Shape संरचना की कल्पना करें: मैं कोड लिख सकता हूं जो Shape से प्राप्त किसी भी संरचना को स्वीकार करता है, और इसके Colour फ़ील्ड तक पहुंचता है, भले ही मैं वर्चुअल Shape.Draw विधि कभी नहीं लिखूं।

मैं एक परिदृश्य के बारे में सोच सकता हूं जो गैर-मुहरबंद मूल्य प्रकारों से टूट जाएगा। मान प्रकार Equals और GetHashCode को सही ढंग से लागू करना चाहिए; भले ही System.Object पर इन दो विधियों को वर्चुअल हैं, फिर भी वे मूल्य प्रकारों पर गैर-वर्चुअल रूप से कॉल किए जाते हैं। यहां तक ​​कि यदि मूल्य प्रकारों को बंद नहीं किया गया था, तो किसी अन्य व्यक्ति से निकाली गई संरचना लिखने वाले व्यक्ति को इन दो विधियों के अपने कार्यान्वयन को नहीं लिखा जा सकता था और उन्हें सही तरीके से बुलाया जाने की उम्मीद थी।

मुझे यह इंगित करना चाहिए कि मैं सुझाव नहीं दे रहा हूं कि मुझे अपने कोड में structs से प्राप्त करने में सक्षम होना चाहिए। मैं जो करने की कोशिश कर रहा हूं, हालांकि, यह अनुमान लगाना है कि यह विशेष कोड गंध क्यों .NET द्वारा प्रतिबंधित है।

संपादित करें 2: मैंने अभी this very similar question देखा है, जिसका उत्तर प्रभावी ढंग से है "क्योंकि तब मान प्रकारों के सरणी काम नहीं करेंगे"।

+0

संभावित डुप्लिकेट [क्यों समर्थन विरासत का समर्थन नहीं करता है?] (Http://stackoverflow.com/questions/1222935/why-dont-structs-support-inheritance) – nawfal

उत्तर

51

कारण यह है कि अधिकांश विरासत तकनीक रनटाइम पॉलीमोर्फिज्म (वर्चुअल फ़ंक्शन) से संबंधित होती हैं और वे मूल्य प्रकारों पर काम नहीं करती हैं: रनटाइम बहुरूपता के लिए कोई अर्थ होने के लिए, वस्तुओं को संदर्भ के रूप में माना जाना चाहिए - यह विशिष्ट नहीं है .NET को या तो, यह केवल तकनीकी विवरण है कि वर्चुअल फ़ंक्शन कैसे कार्यान्वित किए जाते हैं।

वैल्यू प्रकार .NET के नियम के लिए अपवाद बनाते हैं, ठीक उसी तरह हल्के ऑब्जेक्ट्स को अनुमति देने के लिए जिन्हें संदर्भों के माध्यम से संकेत की आवश्यकता नहीं होती है। तो रनटाइम बहुरूपता उनके लिए काम नहीं करती है और विरासत के अधिकांश पहलू अर्थहीन बन जाते हैं।

(एक अपवाद है: एक मान प्रकार ऑब्जेक्ट को बॉक्स किया जा सकता है, जो वर्चुअल विधियों को System.Object से विरासत में प्राप्त करने के लिए अनुमति देता है।)

अपने अंक में से एक के समाधान के लिए:

  • आप आधार के लिए एक व्युत्पन्न struct से डाली सका, क्योंकि वे एक ही स्मृति ओवरलैप होगा।

नहीं, यह संभव नहीं होगा - एक मान प्रकार की नक़ल की अपने मूल्य कास्टिंग। हम यहां संदर्भों से निपट नहीं रहे हैं, इसलिए स्मृति में कोई ओवरलैप नहीं है। मूल्य प्रकार को उसके मूल प्रकार में कास्टिंग करना अर्थहीन है (फिर भी, जब तक हम object पर रूपांतरण के बारे में बात नहीं कर रहे हैं जो वास्तव में हुड के तहत मुक्केबाजी करता है, और भीमूल्य पर मूल्य के अनुसार संचालित होता है)।

अभी भी स्पष्ट नहीं है? चलिए एक उदाहरण देखें।

मान लें कि हमें hypothetical struct Shape मिला है, और इसे struct Circle से प्राप्त किया गया है। Shape वर्चुअल Draw विधि (जो Graphics ऑब्जेक्ट स्वीकार करता है) को परिभाषित करता है। अब, मान लीजिए कि हम कैनवास पर एक आकृति खींचना चाहते हैं। यह, ज़ाहिर है, पूरी तरह से अच्छी तरह से काम करता है:

var circle = new Circle(new Point(10, 10), 20); 
circle.Draw(e.Graphics); // e.Graphics = graphics object of our form. 

- लेकिन यहां हम वास्तव में विरासत का उपयोग नहीं करते हैं। विरासत का उपयोग करने के लिए, के बजाय कल्पना निम्नलिखित DrawObject सहायक विधि:

void DrawObject(Shape shape, Graphics g) { 
    // Do some preparation on g. 
    shape.Draw(g); 
} 

और हम इसे कहीं और फोन एक Circle साथ:

var circle = new Circle(new Point(10, 10), 20); 
DrawObject(circle, e.Graphics); 

- और, का-blam - इस कोड नहीं करता ' एक सर्कल आकर्षित नहीं करते हैं। क्यूं कर?

  • हम प्रतिलिपि यह: क्योंकि जब हम DrawObject विधि के चक्र से गुजरती हैं, हम दो बातें करते हैं।
  • हम टुकड़ा यह, यानी ऑब्जेक्ट shape ऑब्जेक्ट वास्तव में Circle नहीं है - न तो मूल और न ही एक प्रति। इसकी बजाय, प्रतिलिपि के दौरान Circle भाग "कटा हुआ" था और केवल Shape भाग बनी हुई है। shape.Draw अब Circle की Shape की Draw विधि को कॉल करता है।

सी ++ में, आप वास्तव में इस व्यवहार का कारण बन सकते हैं। इसी कारण से, सी ++ में ओओपी केवल पॉइंटर्स और संदर्भों पर काम करता है, न कि मूल्य प्रकारों पर सीधे। और इसी कारण से, .NET केवल संदर्भ प्रकारों की विरासत की अनुमति देता है क्योंकि आप इसे किसी भी प्रकार के मान प्रकारों के लिए उपयोग नहीं कर सके।

ध्यान दें कि उपरोक्त कोड Shape एक इंटरफ़ेस है .NET में काम करता है। दूसरे शब्दों में, संदर्भ प्रकार। अब स्थिति अलग है: आपकी circle ऑब्जेक्ट अभी भी कॉपी की जाएगी लेकिन इसे संदर्भ में भी बॉक्स किया जाएगा।

अब, नेट सैद्धांतिक रूप से आप एक class से एक struct वारिस की अनुमति दे सकती। फिर उपरोक्त कोड बस काम करेगा और साथ ही Shape एक इंटरफेस था। लेकिन फिर, पहली जगह struct होने का पूरा लाभ गायब हो जाता है: सभी उद्देश्यों और उद्देश्यों के लिए (स्थानीय चर के अलावा कभी किसी अन्य विधि को पारित नहीं किया जाता है, इसलिए विरासत की कोई उपयोगिता नहीं) आपके struct एक अपरिवर्तनीय संदर्भ के रूप में व्यवहार करेंगे एक मूल्य प्रकार के बजाय टाइप करें।

+0

पुन "एक मूल्य प्रकार कास्टिंग इसकी मूल्य कॉपी करेगा "- आईएल में, संरचना पर एक विधि संरचना के लिए एक सूचक स्वीकार करती है, इसकी एक प्रति नहीं, इसलिए आधार पर कॉलिंग विधियां अभी भी काम कर सकती हैं। उदाहरण के लिए, "42.ToString()" संकलित करने के लिए, कंपाइलर को एक अस्थायी स्थानीय आवंटित करना होगा, उसमें संख्या 42 डालें, और उसका पता लें। –

+0

@ टिम: आप स्थानीय वस्तुओं पर वर्चुअल विधियों को कभी भी कॉल नहीं करते हैं, जो कोई समझ नहीं लेते हैं। आप केवल पैरामीटर (या पसंद) के माध्यम से पारित मानों पर ऐसा करते हैं और * वहां * आपको संदर्भ के बजाय एक (कटा हुआ) प्रति प्राप्त होगी। –

+0

"आकार आभासी ड्रा विधि को परिभाषित करता है" - वैसे भी काम नहीं करेगा, क्योंकि मान प्रकारों में वर्चुअल विधियां नहीं हैं। आभासी तरीकों के बिना, विरासत सीमित है, लेकिन बेकार नहीं है। –

8

ईसीएमए 335: मूल्य प्रकारों को मूल्य निर्धारण की जटिलताओं से निपटने से बचने के लिए सील कर दिया जाएगा। यहां निर्दिष्ट अधिक प्रतिबंधक नियम गंभीर रूप से समझौता कार्यक्षमता के बिना अधिक कुशल कार्यान्वयन की अनुमति देते हैं।

मुझे नहीं पता कि 'मूल्य निर्धारण' का अर्थ क्या है, लेकिन मुझे लगता है कि उन्हें सीएलआर के कुशल कार्यान्वयन की अनुमति देने के लिए बंद कर दिया गया है।

0

क्योंकि मूल्य-प्रकार के प्रत्येक उदाहरण में अलग-अलग आकार हैं और ढेर पर संग्रहीत हैं। इसलिए, यदि आप "बेस = व्युत्पन्न" लिखते हैं जहां "बेस" और "व्युत्पन्न" मूल्य-प्रकार हैं तो आप ढेर को दूषित करेंगे।

1

आपके पास मूल्य प्रकारों पर जेनेरिक प्रकार पैरामीटर का उपयोग करके विरासत का कुछ सीमित रूप हो सकता है।

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

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