2012-06-14 18 views
18

जब एक विरासत वर्ग इनहेरिट, नए/ओवरराइड व्यवहार नहीं है कि मैं क्या उम्मीद करेंगे:इस विरासत idiosyncrasy के लिए उपयोग केस क्या है?

$ cat Program.cs 
using System; 

class A { 
    public virtual void SayHi() { 
     Console.WriteLine("From A"); 
    } 
} 
class B : A { 
    public new virtual void SayHi() { 
     Console.WriteLine("From B"); 
    } 
} 
class C : B { 
    public override void SayHi() { 
     Console.WriteLine("From C"); 
    } 
} 

public class Program { 
    public static void Main() { 
     A p = new C(); 
     p.SayHi(); 
    } 
} 

$ ./Program.exe 
From A 

क्लास सी के रूप में ओवरराइड करता है SayHi() विधि मैं उत्पादन From C होने की अपेक्षा करेंगे। बी क्लास के new संशोधक को प्राथमिकता क्यों लेती है? इसके लिए उपयोग का मामला क्या है? खासकर जब यह वास्तव में ए

पर ध्यान देने के स्पष्ट उपयोग मामले को तोड़ता है ध्यान दें कि उपरोक्त कोड मोनो 2.10 पर डेबियन-व्युत्पन्न डिस्ट्रो पर चल रहा था। लेकिन मैंने एमएस विजुअल स्टूडियो में सी # कंपाइलर का उपयोग करके एक ही व्यवहार की पुष्टि की है।

+2

'' b' से new' में आभासी अधिभार छिपा है 'C'। 'बी' टाइप करने के लिए' p' बदलें और आपको 'सी' – asawyer

+0

से आउटपुट दिखाई देगा प्रश्न यह है कि "इसके लिए उपयोग केस क्या है?" लेकिन वास्तविक सवाल पूछा गया है "यह ऐसा क्यों करता है?"। मैं उत्सुक हूं कि इसके लिए उपयोग का मामला क्या है - जानबूझकर विरासत को इस तरह से पराजित करना जो आपके एपीआई के उपभोक्ताओं के लिए स्पष्ट नहीं है, अविश्वसनीय रूप से खतरनाक लगता है। – Chuu

+0

@ कुहू: धन्यवाद, मैंने स्पष्ट किया। – dotancohen

उत्तर

21

new modifier सदस्य छिपाने का कारण बनता है, जो आपके वर्ग पदानुक्रम में बहुलक संबंध को तोड़ देता है। SayHiB की विधि (ओवरराइड नहीं) A (इस प्रकार कीवर्ड के रूप में "नया" शब्द का विकल्प) के रूप में माना जाता है। C की विधि B की ओवरराइड करता है, A (जो छुपा रहता है) ओवरराइड करता है।

इसलिए, जब आप एक A संदर्भ के माध्यम से एक C उदाहरण पर SayHi कहते हैं, क्रम में यह A प्रकार, नहीं C प्रकार (जो भीतर SayHi एक 'नई' B से विरासत में मिली विधि है) के खिलाफ हल होगा।

दूसरे हाथ पर, आप को चलाने के लिए थे, हैं:

B p = new C(); 
p.SayHi(); 

... क्या तुम करोगी उम्मीद बहुरूपी परिणाम प्राप्त: चूंकि आप एक यूज़-केस का अनुरोध:

From C 

संपादित , यहां एक है। .NET Framework 2.0 में जेनेरिक की शुरूआत से पहले, सदस्य छिपाने को कभी-कभी व्युत्पन्न कक्षाओं में विरासतित विधियों के कुछ प्रकारों को बदलने के साधन के रूप में उपयोग किया जाता था (कुछ ऐसा जो आप ओवरराइड करते समय नहीं कर सकते) ताकि अधिक विशिष्ट प्रकार लौटा सकें। उदाहरण के लिए:

class ObjectContainer 
{ 
    private object item; 

    public object Item 
    { 
     get { return item; } 
     set { item = value; } 
    } 
} 

class StringContainer : ObjectContainer 
{ 
    public new virtual string Item 
    { 
     get { return base.Item as string; } 
     set { base.Item = value as string; } 
    } 
} 

class QuotedStringContainer : StringContainer 
{ 
    public override string Item 
    { 
     get { return "\"" + base.Item + "\""; } 
    } 
} 

ObjectContainer वर्ग के Item संपत्ति एक सादे object देता है। हालांकि, StringContainer में, इस विरासत में संपत्ति string बदले में छिपी हुई है। इस प्रकार:

ObjectContainer oc = new StringContainer(); 
object o = oc.Item; // Valid, since ObjectContainer.Item is resolved 
string s1 = oc.Item; // Not valid, since ObjectContainer.Item is still resolved 
string s2 = ((StringContainer)oc).Item; 
         // Valid, since StringContainer.Item is now resolved 

QuotedStringContainer वर्ग StringContainer, अपने string वापसी प्रकार इनहेरिट की Item संपत्ति को ओवरराइड करता है; हालांकि, यह अभी भीobject से छिपा हुआ है ItemObjectContainer की संपत्ति को पीछे हटाना। यदि यह इस तरह से नहीं थे, वहाँ उनकी विषम वापसी प्रकार का मिलान का कोई रास्ता नहीं होगा ...

ObjectContainer oc = new QuotedStringContainer(); 
object o = oc.Item; // Valid, since ObjectContainer.Item is resolved 
string s1 = oc.Item; // Not valid, since ObjectContainer.Item is still resolved 
string s2 = ((StringContainer)oc).Item; 
         // Valid, since QuotedStringContainer.Item is now resolved 
         // (polymorphism!) 
string s3 = ((QuotedStringContainer)oc).Item; 
         // Valid, since QuotedStringContainer.Item is now resolved 
+0

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

+1

चूंकि 'सी' 'बी' से निकला है, जो 'ए' से निकला है, इसलिए 'सी' और' ए' के बीच कोई प्रत्यक्ष बहुलक संबंध नहीं है, लेकिन केवल 'बी' के माध्यम से एक अप्रत्यक्ष है। यदि 'बी'-' ए' श्रृंखला टूट जाती है, तो 'सी' का 'ए' का कोई और दावा नहीं है, क्योंकि' बी' ने चैनल – Douglas

+0

तोड़ दिया, मुझे लगता है कि यह समझ में आता है। धन्यवाद डगलस। – dotancohen

7

C विधि के shadowed संस्करण (जो B में shadowed किया जा रहा है) अधिभावी जाता है और A में एक अधिभावी नहीं ।

परिणाम के रूप में, जब आप प्रकार A के एक चर का उपयोग कर रहे, SayHiA में परिभाषित कहा जाता है, के रूप में यह C में ओवरराइड नहीं कर रहा है।

6

CB की विधि ओवरराइड करता है, इसलिए जब आप इसे A पर डाल देते हैं, तो आप आभासी को A में परिभाषित करते हैं।

17.5.3 के तहत ECMA 334: C# Language Specification देखें आपका उदाहरण काफी अधिक है (पृष्ठ 2 9 4)।

+0

लिंक और पृष्ठ के उल्लेख के लिए धन्यवाद। मुझे अभी भी इस व्यवहार के लिए उपयोग का मामला नहीं दिख रहा है, हालांकि, बी के बावजूद ए से सी ओवरराइड करने का उपयोग मामला काफी स्पष्ट है। – dotancohen

2

क्योंकि सी क्लास ए क्लास में सईएचआई विधि को ओवरराइड नहीं कर रही है, इसलिए यह बी में 'नई' विधि को ओवरराइड कर रहा है क्योंकि आपकी कास्ट ए है, इसलिए संकलक हल करता है कि ए.ए.एच.आई.आई. (सी। एसएचआईआई()

2

इस एमएसडीएन पृष्ठ से अंतिम example यहां क्या हो रहा है इसके बारे में बताता है।

मूल रूप से नया संशोधक ए में विधि को सी से छिपाने का कारण बनता है, और चूंकि यह सार्वजनिक होता है जब सी ओवरराइड करता है तो यह बी से विधि को ओवरराइड करता है (जिसे इसकी अपनी विशिष्ट विधि माना जाता है)।

आप निजी करने के लिए बी में विधि सेट करते हैं, सी फिर ए में विधि ओवरराइड कर देगा में

class B : A 
{ 
    private new void SayHi() 
    { 
     Console.WriteLine("From B"); 
    } 
} 

परिणाम: From C

+0

धन्यवाद, लेकिन वह उदाहरण निजी तरीकों से संदर्भित है। – dotancohen

+0

@ डॉटनकोहेन हां, क्योंकि 'बी' प्राइवेट में विधि बनाने से अंतर्निहित 'ए' विधि को 'सी' को ओवरराइड करने के लिए खुलासा किया जाता है, जिससे अपेक्षित परिणाम मिलते हैं। चूंकि आपके पास सार्वजनिक 'बी' विधि है, इसलिए इसे ओवरराइड किया जा रहा है। – NominSim