2017-01-31 9 views
14

मुझे यह समझना शुरू हो गया है कि मुझे समझ में नहीं आता कि क्या हो रहा है।विरासत कक्षाओं में अधिभार विधियां

public class Base 
{ 
    public void Method(D a) 
    { 
     Console.WriteLine("public void Method(D a)"); 
    } 
} 

public class Derived: Base 
{ 
    public void Method(B a) 
    { 
     Console.WriteLine("public void Method(B a)"); 
    } 
} 

public class B { } 

public class D: B { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Derived derived = new Derived(); 
     D d = new D(); 

     derived.Method(d); 
    } 
} 

यह प्रिंट होगा

public void Method(B a)

बजाय

public void Method(D a)

यह आश्चर्य की बात है: वहाँ सी # में निम्नलिखित व्यवहार है। मुझे लगता है कि इस व्यवहार का कारण विधियों की तालिका का कार्यान्वयन है। यदि सीएलआर वर्तमान प्रकार में संबंधित विधि पाता है तो सीएलआर बेस क्लास में विधियों की खोज नहीं करता है। मुझे लगता है कि वे प्रदर्शन में सुधार करने की कोशिश कर रहे थे।

लेकिन मैं निम्न कोड के साथ पूरी तरह से निराश था:

public class Base 
{ 
    public virtual void Method(D a) 
    { 
     Console.WriteLine("public void Method(D a)"); 
    } 
} 

public class Derived: Base 
{ 
    public override void Method(D a) 
    { 
     Console.WriteLine("public override void Method(D a)"); 
    } 

    public void Method(B a) 
    { 
     Console.WriteLine("public void Method(B a)"); 
    } 

} 

public class B { } 

public class D: B { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Derived derived = new Derived(); 
     D d = new D(); 

     derived.Method(d); 
    } 
} 

और यह

public void Method(B a)

बजाय

public override void Method(D a)

यह भयानक और बहुत unpred है प्रिंट होगा ictable।

क्या कोई इसे समझा सकता है?

मुझे लगता है कि विधि तालिका में विधियों को केवल वर्तमान प्रकार में लागू किया गया है (ओवरराइडिंग विधियों को छोड़कर) और सीएलआर किसी भी विधि के रूप में जल्द ही संबंधित विधि की तलाश में बंद हो जाता है। क्या मैं सही हू?

+3

विधि तालिका में यह विशिष्ट प्रकार में हस्ताक्षर के साथ विधि की तलाश कर रहा है जिस पर विधि कहा जाता है और यह एक मैच पाता है क्योंकि डी भी विरासत के अनुसार बी है, और यह ओवर्रिडेन विधि –

+0

@EhsanSajjad प्रश्न की उपेक्षा कर रहा है है * क्यों * यह दूसरे पर अधिभार चुन रहा है। दोनों वैध विधि कॉल हैं, लेकिन संकलक दूसरे पर एक चुनता है। – Servy

+1

'सीएलआर जैसे ही किसी भी विधि को बुलाया जा सकता है, संबंधित विधि की तलाश करना बंद कर देता है। क्या मैं सही हूँ? इसका सीएलआर से कोई लेना देना नहीं है। यह सी # चश्मा के आधार पर सी # कंपाइलर द्वारा पूरी तरह से संकलित समय निर्णय है, रनटाइम द्वारा किए गए निर्णय नहीं। – Servy

उत्तर

15

मुझे यह समझना शुरू हो गया है कि मुझे समझ में नहीं आता कि क्या हो रहा है।

इस प्रकार ज्ञान शुरू होता है।

यह भयानक और बहुत अप्रत्याशित है।

यह न तो है। इसके विपरीत, सुविधा को द्वारा अप्रत्याशितता को भंगुर आधार वर्ग विफलता के कारण को समाप्त करने के लिए डिज़ाइन किया गया है।

क्या कोई इसे समझा सकता है?

इस विषय पर मेरा 2007 लेख देखें।

https://blogs.msdn.microsoft.com/ericlippert/2007/09/04/future-breaking-changes-part-three/

लघु संस्करण हालांकि है: एक व्युत्पन्न वर्ग में एक विधि हमेशा एक आधार वर्ग में एक विधि की तुलना में बेहतर है, व्युत्पन्न वर्ग लिखने वाले व्यक्ति को ऑब्जेक्ट सेमेन्टिक्स के बारे में और पता है और बेस क्लास लिखने वाले व्यक्ति की तुलना में अधिक विशिष्ट केस को संभालने वाला है।

सेवा बताते हैं कि मैंने आपके दूसरे बिंदु को कवर नहीं किया है। व्युत्पन्न वर्ग में ओवरराइड क्यों व्युत्पन्न वर्ग में "डी" विधि नहीं बनाता है?

आभासी तरीकों वर्ग जहां वे, नहीं वर्ग जहां वे सबसे हाल ही में अधिरोहित गया की घोषित किया गया की तरीकों माना जाता है। क्यूं कर? क्योंकि ओवरराइड करने या नहीं चुनने के लिए कक्षा का कार्यान्वयन विवरण है, और सार्वजनिक सतह क्षेत्र का हिस्सा नहीं है।

मेरा मतलब है, इसके बारे में सोचें। आप कुछ कोड लिखते हैं, यह काम करता है, और फिर आप कहते हैं, हे, मैं इस विधि के कहीं भी इस विधि पदानुक्रम में एक नया (या पुराना निकालना) ओवरराइड करने जा रहा हूं, और अचानक ओवरलोड रिज़ॉल्यूशन बदलता है कहीं और? यह वास्तव में इतनी दयालुता है कि सी # खत्म करने की कोशिश करता है।

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

+1

@ सर्वी: एक वर्चुअल विधि को उस प्रकार की विधि माना जाता है जो इसे घोषित करता है, न कि जिस प्रकार से इसे ओवरलोड करता है। लेकिन यह एक सूक्ष्म बिंदु है। मैं जवाब में एक नोट जोड़ दूंगा। –

1

मैं यहां भ्रम देख सकता हूं। एरिक का जवाब एक उदाहरण के साथ बेहतर चित्रित किया जा सकता है। यदि आपने कोड को निम्नानुसार बदल दिया है ...

public class Base 
{ 
    public virtual void Method(D a) 
    { 
     Console.WriteLine("public void Method(D a)"); 
    } 

    public void Method(B a) 
    { 
     Console.WriteLine("public void Method(B a)"); 
    } 
} 

public class Derived : Base 
{ 
    public override void Method(D a) 
    { 
     Console.WriteLine("public override void Method(D a)"); 
    } 

} 

public class B { } 

public class D : B { } 

आउटपुट "सार्वजनिक ओवरराइड शून्य विधि (डी ए)" बन जाता है।

क्यों?

के रूप में एरिक के लेख में कहा गया है ... एक आधार वर्ग में

तरीकों उम्मीदवारों अगर एक व्युत्पन्न कक्षा में किसी भी विधि लागू

दोनों विधि (डी) और विधि के रूप में है नहीं कर रहे हैं (बी) अब बेस क्लास में हैं, विधि (डी) निकटतम मैच बन गया है जो आपके व्युत्पन्न वर्ग में आउटपुट से अधिक है।

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

मुझे लगता है कि ओओपी के लिए नए लोगों द्वारा बनाई गई एक आम गलती विरासत के नए खिलौने का उपयोग करना है। विरासत अक्सर ओओडी में इस्तेमाल किए जाने वाले पसंदीदा संबंध नहीं है। जब आप ओओपी डिजाइन पैटर्न का अध्ययन शुरू करते हैं तो आप ध्यान देंगे कि कई पैटर्न विरासत का उपयोग नहीं करते हैं।

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

विरासत एक शक्तिशाली निर्माण है, जैसा कि सबसे शक्तिशाली चीजों के साथ, इसे कम से कम और देखभाल के साथ उपयोग किया जाना चाहिए।

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