2011-09-02 21 views
6

मेरे पास एक ऐसी स्थिति है जिसमें मैं बेस क्लास की विधि को ओवरराइड करना चाहता हूं ताकि विधि के रिटर्न प्रकार को थोड़ा बदल दिया जा सके। थोड़ा करके बदल मैं एक वस्तु है कि वस्तु है कि आधार प्रकार में विधि द्वारा लौटा दिए गए हैं से विरासत लौट मतलब ... वास्तव में, एक छोटे से कोड इस आसानवापसी प्रकार बदलने के लिए ओवरराइडिंग विधि

class Program 
{ 
    static void Main(string[] args) 
    { 
     var obj = new ParentClass(); 
     Console.WriteLine("Parent says: " + obj.ShowYourHand()); 

     var obj2 = new ChildClass(); 
     Console.WriteLine("Child says: " + obj2.ShowYourHand()); 

     Console.ReadLine(); 
    } 
} 

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = GetExternalObject(); 
     return obj.ToString(); 
    } 
    protected virtual ExternalObject GetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    protected virtual new ExternalObjectStub GetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
} 

public class ExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObject"; 
    } 
} 

public class ExternalObjectStub : ExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObjectStub"; 
    } 
} 

मुद्दा रहा होगा ... यह है कि obj2 का उदाहरण GetExternalObject() का संस्करण नहीं कहता है बल्कि इसके माता-पिता के कार्यान्वयन का उपयोग करता है।

मुझे लगता है कि इसकी वजह कोड

var obj = GetExternalObject(); 

obj के प्रकार के माता-पिता कक्षा में ExternalObject होने की उम्मीद है में ऐसा कर रही है। मुझे समझ में आया कि सी # वापसी प्रकार के आधार पर विधियों के बीच अंतर नहीं कर सकता है।

मुझे पता है कि इस मुद्दे के अन्य समाधान हैं जैसे कि IExternalObject को परिभाषित करना, इसलिए इसके बारे में भी लटका न लें। मैं बस इतना जानना चाहता था कि क्या सोच रहा है कि बाल वर्गों को GetExternalObject को बाल वर्ग द्वारा भी बुलाया जाने से रोकता है?

या क्या मैं पूरी तरह से कुछ कर रहा हूं? :-)

+0

इसी प्रकार के प्रश्न: [सी #: अधिभावी वापसी प्रकार] (http://stackoverflow.com/questions/1048884/c-overriding-return-types) की [सी #: अधिभावी वापसी प्रकार] –

+0

संभावित डुप्लिकेट (https : //stackoverflow.com/questions/1048884/c-overriding-return-types) –

उत्तर

7

या क्या मैं पूरी तरह से कुछ कर रहा हूं? :-)

हाँ, आप हैं। आप इसे ओवरराइड करके विधि के रिटर्न प्रकार को नहीं बदल सकते हैं। मैं इसे अपने नमूने में वैसे भी समझ में नहीं आता। बस रिटर्न प्रकार को छोड़ दें और एक नया ExternalObjectStub वापस करें। यह काम करता है, क्योंकि ExternalObjectStubExternalObject से निकला है।

आधार सदस्य को new के साथ छुपाकर वापसी प्रकार को बदलकर, यह आमतौर पर एक बहुत बुरा विचार है, क्योंकि यह उस वर्ग की ओर जाता है जिसका उपयोग पॉलिमॉर्फिक तरीके से नहीं किया जा सकता है। यह वही है जो आप यहां अनुभव कर रहे हैं: यदि संदर्भ रखने वाले वेरिएबल का प्रकार ParentClass है, तो यह विधि 10 में विधि को कॉल करती है, भले ही उदाहरण वास्तव में ChildClass टाइप हो, क्योंकि ChildClass ओवरड्रिडेन कार्यान्वयन प्रदान नहीं करता है GetExternalObject

4

पॉलिमॉर्फिज्म जैसा कि आप इसका उपयोग कर रहे हैं, सही नहीं है। आपको अपने बच्चे वर्ग में एक नई विधि बनाने की आवश्यकता है जो नए रिटर्न प्रकार के साथ बेस क्लास के कार्यान्वयन को छुपाता है। आप एक विधि को अधिभारित करने के लिए वर्चुअल विधियों का उपयोग नहीं कर सकते हैं जैसे आप कर रहे हैं।

वर्चुअल विधियों का उपयोग बच्चे वर्ग में एक विधि के कार्यान्वयन को कार्यान्वित करने के लिए किया जाता है, न कि "ओवरलोड" करने के लिए, जैसा कि आप करने की कोशिश कर रहे हैं।

पैरामीटर को बदलकर विधियों को ओवरलोड करना, रिटर्न प्रकार नहीं।

तो या तो बच्चे वर्ग में, मूल विधि को छुपाएं, या किसी अन्य नाम के साथ एक विधि बनाएं। इसके लिए वर्चुअल का उपयोग करना काम नहीं करेगा।

0

आप बच्चे को कक्षा में ExternalObjectStub वापस जाने के लिए चाहते हैं, तो इस ExternalObjectStub ExternalObject वर्ग

2

से निकाले जाते हैं चाहिए आप अपने कक्षाएं, एक अंतरफलक लौट प्रत्येक वर्ग (ParentClass और ChildClass) इंटरफेस का एक उदाहरण लौटने के साथ होना चाहिए।आपको अपने ChildClass में GetExternalObject विधि को ओवरराइड करना चाहिए ताकि वी-टेबल सही कार्यान्वयन को इंगित करे।

इसके अलावा, आपके कोड में टाइपो था - Main विधि obj दो बार संदर्भित करती है जब आप ShowYourHand पर कॉल कर रहे थे। मैंने इसे obj और obj2 संदर्भित करने के लिए भी बदल दिया। यहां आपके द्वारा किसी इंटरफेस (और मुख्य में obj टाइपो फिक्सिंग) के साथ इस को लागू कर सकते हैं:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var obj = new ParentClass(); 
     Console.WriteLine("Parent says: " + obj.ShowYourHand()); 

     var obj2 = new ChildClass(); 
     Console.WriteLine("Child says: " + obj2.ShowYourHand()); 

     Console.ReadLine(); 
    } 
} 

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = this.GetExternalObject(); 
     return obj.ToString(); 
    } 
    protected virtual IExternalObject GetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    protected override IExternalObject GetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
} 

public interface IExternalObject { } 

public class ExternalObject : IExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObject"; 
    } 
} 

public class ExternalObjectStub : IExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObjectStub"; 
    } 
} 
2

मुझे नहीं लगता कि आप कुछ भी Daft कर रहे है। मैं खुद को इस पैटर्न को लागू करने के तरीकों की तलाश में अक्सर ढूंढता हूं (कक्षा फू में टाइप बार, क्लास फूसब की संपत्ति है: फू उस संपत्ति को बारसब: बार के प्रकार के रूप में बेनकाब करने में सक्षम होना चाहिए)।

"नया" ऑपरेटर के बारे में समझने के लिए एक महत्वपूर्ण बात यह है कि यह केवल उपclass पर कार्यान्वयन को छुपाता है। यदि सबक्लास को बेस क्लास में वापस डाला जाता है, तो बेस क्लास के कार्यान्वयन का उपयोग इसके बजाय किया जाता है। तो आप यह सुनिश्चित करना चाहते हैं कि आपके पास ओवरराइड करने के लिए "असली" विधि है ताकि जब भी ऐसा होता है, यह अभी भी उचित प्रकार को वापस कर रहा है।

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = GetExternalObject(); 
     return obj.ToString(); 
    } 

    protected ExternalObject GetExternalObject() 
    { 
     return this.RealGetExternalObject(); 
    } 

    protected virtual ExternalObject RealGetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    new protected ExternalObjectStub GetExternalObject() 
    { 
     return (ExternalObjectStub)this.RealGetExternalObject(); 
    } 

    protected override ExternalObject RealGetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
} 
संबंधित मुद्दे