2009-04-05 13 views
30

कहें कि मेरे पास सी # विधि के दो अधिभारित संस्करण हैं:सी #: ओवरलोडेड विधि के लिए शून्य पास - कौन सी विधि कहा जाता है?

void Method(TypeA a) { } 
void Method(TypeB b) { } 

मैं इस विधि को कॉल करता हूं:

Method(null); 

विधि का कौन सा अधिभार कहा जाता है? यह सुनिश्चित करने के लिए मैं क्या कर सकता हूं कि एक विशेष अधिभार कहा जाता है?

+0

एक और एक कॉल कर सकते हैं की ओवरलोड हो गया है तरीकों जहां कम से कम एक विधि पैरामीटर कीवर्ड का उपयोग करता है के बारे में पता किया जाना है। –

उत्तर

67

यह TypeA और TypeB पर निर्भर करता है।

  • तो वास्तव में उनमें से एक पर लागू होता है तो कॉल लागू एक करने के लिए किया जाएगा (जैसे वहाँ TypeB को null से कोई रूपांतरण है क्योंकि यह एक मान प्रकार है, लेकिन TypeA एक संदर्भ प्रकार है)।
  • अन्यथा यह TypeA और TypeB के बीच संबंधों पर निर्भर करता है।
    • अगर वहाँ TypeA से TypeB को एक अंतर्निहित रूपांतरण लेकिन TypeBTypeA करने से कोई अंतर्निहित रूपांतरण तो TypeA का उपयोग कर अधिभार का उपयोग किया जाएगा।
    • अगर वहाँ TypeB से TypeA को एक अंतर्निहित रूपांतरण लेकिन TypeATypeB करने से कोई अंतर्निहित रूपांतरण तो TypeB का उपयोग कर अधिभार का उपयोग किया जाएगा।
    • अन्यथा, कॉल संदिग्ध है और संकलित करने में विफल हो जाएगा।

देखें अनुभाग विस्तृत नियम के लिए सी # 3.0 कल्पना की 7.4.3.4।

यहां इसका एक उदाहरण अस्पष्ट नहीं है। यहां TypeBTypeA से निकला है, जिसका अर्थ है कि TypeB से TypeA तक एक अंतर्निहित रूपांतरण है, लेकिन इसके विपरीत नहीं। इस प्रकार TypeB का उपयोग कर अधिभार प्रयोग किया जाता है:

using System; 

class TypeA {} 
class TypeB : TypeA {} 

class Program 
{ 
    static void Foo(TypeA x) 
    { 
     Console.WriteLine("Foo(TypeA)"); 
    } 

    static void Foo(TypeB x) 
    { 
     Console.WriteLine("Foo(TypeB)"); 
    } 

    static void Main() 
    { 
     Foo(null); // Prints Foo(TypeB) 
    } 
} 

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

Foo((TypeA) null); 

या

Foo((TypeB) null); 

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

+0

@ जोन: इस मामले में जैसा व्यवहार आप वर्णन करते हैं वह एक निहित रूपांतरण उपलब्ध क्यों है? मैं इसके विपरीत की उम्मीद करूँगा। क्या यह सिर्फ परिभाषा का मामला है? –

+2

@divo: यह निश्चित रूप से एक डिज़ाइन निर्णय है, लेकिन शायद इसके पीछे कारण यह है कि TypeB विधि टाइपए विधि का एक विशेष मामला है। मेरा मतलब है, प्रत्येक वैध तर्क के लिए, डिफ़ॉल्ट टाइपए से तब तक मिलान किया जाएगा जब तक ऑब्जेक्ट टाइपब के रूप में जाना जाता है। शून्य के लिए यह व्यवहार इस स्थिरता को सुनिश्चित करता है। –

+0

मेहरदड सही है - यदि आप टाइपब से टाइपए में परिवर्तित कर सकते हैं, तो TypeB टाइपए से अधिक विशिष्ट है, इसलिए वरीयता में चुना जाएगा। –

1

अस्पष्ट कॉल। (समय त्रुटि संकलित)।

+0

हाय, मैंने नमूना निम्नलिखित करने की कोशिश की और संकलन त्रुटि नहीं मिली; कोई विचार क्यों? कक्षा कार्यक्रम { शून्य परीक्षण 1 (आईसीओलेक्शन ए) { कंसोल। राइटलाइन ("test1-ICollection"); } शून्य परीक्षण 1 (IList ए) { कंसोल। राइटलाइन ("test1-list"); } स्थैतिक शून्य मुख्य (स्ट्रिंग [] तर्क) { प्रोग्राम पी = नया प्रोग्राम(); p.test1 (शून्य); कंसोल। रीडकी(); } } –

+0

लेकिन मैं त्रुटि संकलन जब मैं प्रकार IComparer वर्ग कार्यक्रम { शून्य test1 के पैरामीटर को स्वीकार करने के भार के में से एक को बदल दिया (IList क) { Console.WriteLine ("test1- मिला सूची"); } शून्य परीक्षण 1 (आईसीओएमपेयर ए) { कंसोल।WriteLine ("test1-IComparer"); } स्थैतिक शून्य मुख्य (स्ट्रिंग [] तर्क) { प्रोग्राम पी = नया प्रोग्राम(); p.test1 (शून्य); कंसोल। रीडकी(); } } –

8

जॉन स्कीट ने एक व्यापक उत्तर दिया है, लेकिन एक डिजाइन बिंदु से आपको संकलक विनिर्देश के कोने-मामलों पर निर्भर नहीं होना चाहिए। यदि कुछ और नहीं है, तो आपको इसे लिखने से पहले क्या करना है, अगले व्यक्ति को इसे पढ़ने की कोशिश करने के लिए यह नहीं पता होगा कि यह क्या करता है। यह रखरखाव योग्य नहीं है।

अधिभार सुविधा के लिए हैं, और एक ही नाम के साथ दो अलग अधिभार एक ही काम करना चाहिए। यदि दो विधियां अलग-अलग चीजें करती हैं, तो उनमें से एक या दोनों का नाम बदलें।

पैरामीटर की अलग-अलग संख्या वाले संस्करणों के लिए ओवरलोडेड विधि के लिए अधिक सामान्य है, और समझदार डिफ़ॉल्ट आपूर्ति करने के लिए कम पैरामीटर के साथ अधिभार के लिए अधिक सामान्य है।

उदा। string ToString(string format, System.IFormatProvider provider) सबसे पैरामीटर,
string ToString(System.IFormatProvider provider) एक डिफ़ॉल्ट प्रारूप की आपूर्ति की है, और
string ToString() एक डिफ़ॉल्ट प्रारूप और प्रदाता,

+0

मुझे ओवरलोड के बारे में आपका बिंदु नहीं दिख रहा है। सच है, ओवरलोड को एक ही चीज़ करना चाहिए, लेकिन यह विभिन्न तरीकों से कर सकता है। यही कारण है कि आप अधिभार चाहते हैं। तर्कों की संख्या अप्रासंगिक है, और यह वही या अलग हो सकती है (बिंदु में मामला: विभिन्न कनवर्ट विधियां)। कंपाइलर स्पेसिफ़िक्स के बारे में: अगले व्यक्ति के कौशल स्तर के आधार पर, कुछ भी «कोने केस» हो सकता है। जब तक आपका डिज़ाइन समझ में आता है, और सहज ज्ञान युक्त तरीके से काम करता है, यह काम करता है। उस पर सावधानीपूर्वक विचार डिजाइन समय की आवश्यकता हो सकती है, जब वर्ग का उपयोग बाद में किया जाता है। –

+0

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

0

एक सरल समाधान के हस्ताक्षर के साथ एक और तरीका बनाने के लिए है की आपूर्ति:

void Method() { } 

या एक विधि पर हस्ताक्षर को अद्यतन करने के लिए बेहतर:

void Method(TypeB b = null) { } 

और फिर मुझे कॉल करें टी के रूप में इतना:

Method(); 

संकलन समय पर मूल्य null untyped और इतने संकलक यह मेल नहीं कर सकते हैं विधि हस्ताक्षर से एक के साथ है। रन टाइम पर null को हल करने वाले किसी भी चर को अभी भी टाइप किया जाएगा और इसलिए इससे कोई समस्या नहीं आएगी।

3

जॉन स्कीट ने पहले से ही उत्तर दिया है कि कौन से ओवरलोड को डिफ़ॉल्ट रूप से चुना जाता है, लेकिन यदि आप यह सुनिश्चित करना चाहते हैं कि विशेष अधिभार कहा जाता है, तो अक्सर कास्ट की तुलना में नामित पैरामीटर का उपयोग करना बेहतर होता है।

यदि आपके पास:

void Method(TypeA a) { } 
void Method(TypeB b) { } 

आप Method(a: null); या Method(b: null);

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