अगर यह अस्पष्टता में शामिल नहीं होगा, तो एक पद्धति को एक अस्पष्ट कॉल क्यों जोड़ा जाएगा


112

मेरी यह क्लास है

public class Overloaded
{
    public void ComplexOverloadResolution(params string[] something)
    {
        Console.WriteLine("Normal Winner");
    }

    public void ComplexOverloadResolution<M>(M something)
    {
        Console.WriteLine("Confused");
    }
}

अगर मैं इसे इस तरह कहता हूं:

        var blah = new Overloaded();
        blah.ComplexOverloadResolution("Which wins?");

यह Normal Winnerकंसोल को लिखता है।

लेकिन, अगर मैं एक और तरीका जोड़ूँ:

    public void ComplexOverloadResolution(string something, object somethingElse = null)
    {
        Console.WriteLine("Added Later");
    }

मुझे निम्नलिखित त्रुटि मिलती है:

कॉल निम्न विधियों या गुणों के बीच अस्पष्ट है:> ' Overloaded.ComplexOverloadResolution(params string[])' और 'Overloaded.ComplexOverloadResolution<string>(string) '

मैं समझ सकता हूं कि कोई विधि जोड़ने से कॉल अस्पष्टता का परिचय हो सकता है, लेकिन यह पहले से मौजूद दो तरीकों के बीच एक अस्पष्टता है (params string[]) और <string>(string)! स्पष्ट रूप से अस्पष्टता में शामिल दो तरीकों में से कोई भी नया जोड़ा गया तरीका नहीं है, क्योंकि पहला एक परम है, और दूसरा एक सामान्य है।

क्या यह बग है? कल्पना का क्या हिस्सा कहता है कि यह मामला होना चाहिए?


2
मुझे नहीं लगता 'Overloaded.ComplexOverloadResolution(string)'कि <string>(string)विधि को संदर्भित करता है ; मुझे लगता है कि यह (string, object)विधि को संदर्भित करता है जिसमें कोई वस्तु नहीं दी जाती है।
phoog

1
@phoog ओह, यह डेटा StackOverflow द्वारा कट गया क्योंकि यह एक टैग है, लेकिन त्रुटि संदेश में टेम्पलेट डिज़ाइनर है। मैं इसे वापस जोड़ रहा हूं।
मैके

तुमने मुझे पकड़ लिया है! मैंने अपने उत्तर में कल्पना के संबंधित खंडों का हवाला दिया, लेकिन मैंने पिछले आधे घंटे को पढ़ने और उन्हें समझने में खर्च नहीं किया है!
फोज

@ फोटो, कल्पना के उन हिस्सों के माध्यम से देख रहा हूं, मुझे खुद के अलावा अन्य तरीकों में अस्पष्टता का परिचय देने के बारे में कुछ भी नहीं है, दो अन्य तरीकों से नहीं।
मैकके

मेरे साथ यह हुआ कि यह केवल रॉक-पेपर-कैंची है : दो अलग-अलग मूल्यों के किसी भी सेट में एक विजेता होता है, लेकिन तीन मानों का पूरा सेट नहीं होता है।
फॉग

जवाबों:


107

क्या यह बग है?

हाँ।

बधाई हो, आपको अधिभार संकल्प में एक बग मिला है। बग सी # 4 और 5 में प्रजनन करता है; यह सिमेंटिक विश्लेषक के "रोसलिन" संस्करण में पुन: पेश नहीं करता है। मैंने C # 5 टेस्ट टीम को सूचित किया है, और उम्मीद है कि हम अंतिम रिलीज से पहले इसकी जांच और हल कर सकते हैं। (हमेशा की तरह, कोई वादा नहीं।)

एक सही विश्लेषण इस प्रकार है। उम्मीदवार हैं:

0: C(params string[]) in its normal form
1: C(params string[]) in its expanded form
2: C<string>(string) 
3: C(string, object) 

उम्मीदवार शून्य स्पष्ट रूप से अनुचित है क्योंकि string यह परिवर्तनीय नहीं है string[]। वह तीन छोड़ देता है।

तीन में से, हमें एक अद्वितीय सर्वोत्तम विधि निर्धारित करनी चाहिए। हम शेष तीन उम्मीदवारों की जोड़ी की तुलना करके बनाते हैं। ऐसी तीन जोड़ियाँ हैं। उन सभी के पास हैएक बार जब हम छोड़े गए वैकल्पिक मापदंडों को छीन लेते हैं, समान पैरामीटर सूची होती है, जिसका अर्थ है कि हमें विनिर्देश के खंड 7.5.3.2 में वर्णित उन्नत टाईब्रेकिंग दौर में जाना है।

कौन सा बेहतर है, 1 या 2? प्रासंगिक टाईब्रेकर यह है कि एक सामान्य विधि हमेशा गैर-जेनेरिक विधि से भी बदतर होती है। 2 1 से भी बदतर है। इसलिए 2 विजेता नहीं हो सकते।

कौन सा बेहतर है, 1 या 3? प्रासंगिक टाईब्रेकर है: केवल विस्तारित रूप में लागू एक विधि हमेशा अपने सामान्य रूप में लागू विधि से भी बदतर होती है। इसलिए 1 3. से भी बदतर है। इसलिए 1 विजेता नहीं हो सकता।

कौन सा बेहतर है, 2 या 3? प्रासंगिक टाईब्रेकर यह है कि एक सामान्य विधि हमेशा गैर-जेनेरिक विधि से भी बदतर होती है। 2 3 से खराब है। इसलिए 2 विजेता नहीं हो सकते।

कई लागू उम्मीदवारों के एक सेट से चुने जाने के लिए एक उम्मीदवार होना चाहिए (1) नाबाद, (2) कम से कम एक अन्य उम्मीदवार को हराए, और (3) पहले दो गुणों वाले अद्वितीय उम्मीदवार हों। उम्मीदवार तीन को किसी अन्य उम्मीदवार द्वारा नहीं पीटा जाता है, और कम से कम एक अन्य उम्मीदवार की पिटाई करता है; यह इस संपत्ति के साथ एकमात्र उम्मीदवार है। इसलिए उम्मीदवार तीन अद्वितीय सबसे अच्छा उम्मीदवार है । इसे जीतना चाहिए।

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

कोई यथोचित पूछ सकता है कि ऐसा क्यों है। यह दो तरीकों को खोजने के लिए काफी मुश्किल है जो "अस्पष्ट रूप से अस्पष्ट" हैं क्योंकि "विश्वासघात" संबंध अकर्मक है । उन स्थितियों के साथ आना संभव है जहां उम्मीदवार 1 2 से बेहतर है, 2 3 से बेहतर है, और 3 1 से बेहतर है। ऐसी स्थितियों में हम उनमें से दो को "अस्पष्ट लोगों" के रूप में चुनने से बेहतर नहीं कर सकते हैं।

मैं रोजलिन के लिए इस अनुमान को सुधारना चाहूंगा लेकिन यह कम प्राथमिकता है।

(पाठक को व्यायाम: "एक रैखिक समय-एल्गोरिथ्म का पता लगाएं, एन तत्वों के एक सेट के अद्वितीय सर्वश्रेष्ठ सदस्य की पहचान करने के लिए जहां विश्वासघात संबंध अकर्मक है" इस सवाल में से एक था जो मुझे इस टीम के लिए साक्षात्कार के दिन पूछा गया था। एक बहुत ही कठिन एल्गोरिथ्म; इसे एक शॉट दें।)

जिन कारणों से हमने C # के लिए वैकल्पिक दलीलों को जोड़ने पर पीछे धकेला, उनमें से कई जटिल अस्पष्ट परिस्थितियों की संख्या थी जो इसे ओवरलोड रिज़ॉल्यूशन एल्गोरिथ्म में पेश करता है; जाहिर तौर पर हम इसे सही नहीं समझ पाए।

यदि आप इसे ट्रैक करने के लिए कनेक्ट मुद्दे को दर्ज करना चाहते हैं, तो स्वतंत्र महसूस करें। यदि आप चाहते हैं कि यह हमारे ध्यान में लाया जाए, तो इस पर विचार करें। मैं अगले साल परीक्षण के साथ पालन करेंगे।

इसे मेरे संज्ञान में लाने के लिए धन्यवाद। त्रुटि के लिए क्षमा याचना।


1
जवाब देने के लिए धन्यवाद। आपने कहा "1 2 से खराब है", लेकिन यह विधि 1 को चुनता है अगर मेरे पास विधि 1 और 2 है?
मैकके

@ मैकके: वूप्स, आप सही कह रहे हैं, मैंने कहा कि पीछे। मैं पाठ ठीक कर दूँगा।
एरिक लिपर्ट

1
यह वाक्यांश पर विचार वहाँ भी आधे से एक सप्ताह के छोड़ दिया :) नहीं है "वर्ष के बाकी" पढ़ने अजीब लगता है
BoltClock

2
@BoltClock वास्तव में, "वर्ष के बाकी दिनों के लिए" बयान एक दिन की छुट्टी का मतलब है।
phoog

1
मुझे ऐसा लगता है। मैं पढ़ता हूं "3) अद्वितीय उम्मीदवार हो सकता है जिसके पास पहले दो गुण हैं" के रूप में "एकमात्र उम्मीदवार हो (जो नाबाद है और कम से कम एक अन्य उम्मीदवार को हराता है)" । लेकिन आपकी सबसे हाल की टिप्पणी मुझे लगता है "(एकमात्र उम्मीदवार है जो नाबाद है) और कम से कम एक अन्य उम्मीदवार को हराता है" । अंग्रेजी वास्तव में समूहीकरण प्रतीकों का उपयोग कर सकती है। यदि उत्तरार्द्ध सच है, तो मैं इसे फिर से प्राप्त करता हूं।
default.kramer

5

कल्पना का क्या हिस्सा कहता है कि यह मामला होना चाहिए?

धारा member.५.३ (अधिभार संकल्प), खंड lookup.४ (सदस्य लुकअप) और type.५.२ (प्रकार की खोज) के साथ।

विशेष रूप से खंड 7.5.3.2 (बेहतर कार्य सदस्य) पर ध्यान दें, जो कहता है "पैरामीटर सूची से कोई संगत तर्क के साथ वैकल्पिक पैरामीटर हटा दिए जाते हैं," और "यदि एम (पी) एक गैर-जेनेरिक विधि एम डी (क्यू) है एक सामान्य विधि, तो M (p) M (q) से बेहतर है। "

हालांकि, मैं कल्पना के इन हिस्सों को पूरी तरह से समझने के लिए पर्याप्त नहीं हूं कि कल्पना के कौन से हिस्से इस व्यवहार को नियंत्रित करते हैं, अकेले यह निर्धारित करने के लिए कि क्या यह आज्ञाकारी है।


लेकिन यह नहीं बताया गया है कि एक सदस्य को जोड़ने से दो विधियों के बीच अस्पष्टता पैदा होगी जो पहले से मौजूद हैं।
मैकके

@ मेकय मेला काफी (देखें संपादित करें)। हमें एरिक
लिपर्ट के

1
वे सभी कल्पना के सही भाग हैं। मुसीबत यह है कि वे कहते हैं कि यह मामला नहीं होना चाहिए !
एरिक लिपर्ट

3

आप कुछ तरीकों में पहले पैरामीटर का नाम बदलकर और उस पैरामीटर को निर्दिष्ट करके इस अस्पष्टता से बच सकते हैं जिसे आप निर्दिष्ट करना चाहते हैं

इस तरह :

public class Overloaded
{
    public void ComplexOverloadResolution(params string[] somethings)
    {
        Console.WriteLine("Normal Winner");
    }

    public void ComplexOverloadResolution<M>(M something)
    {
        Console.WriteLine("Confused");
    }

    public void ComplexOverloadResolution(string something, object somethingElse = null)
    {
        Console.WriteLine("Added Later");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Overloaded a = new Overloaded();
        a.ComplexOverloadResolution(something:"asd");
    }
}

ओह, मुझे पता है कि यह कोड खराब है, और इसके चारों ओर काम करने के कई तरीके हैं, सवाल था "कंपाइलर इस तरह से व्यवहार क्यों करता है?"
मैकके

1

यदि आप paramsअपनी पहली विधि से हटाते हैं , तो ऐसा नहीं होगा। आपके पास पहली और तीसरी विधि में दोनों वैध कॉल हैं ComplexOverloadResolution(string), लेकिन यदि आपकी पहली विधि है public void ComplexOverloadResolution(string[] something)तो कोई अस्पष्टता नहीं होगी।

एक पैरामीटर के लिए मान लेना object somethingElse = nullइसे वैकल्पिक पैरामीटर बनाता है और इस प्रकार उस अधिभार को कॉल करते समय निर्दिष्ट नहीं करना पड़ता है।

संपादित करें: संकलक यहां कुछ पागल सामान कर रहा है। यदि आप अपने पहले के बाद अपने तीसरे तरीके को कोड में स्थानांतरित करते हैं, तो यह सही ढंग से रिपोर्ट करेगा। ऐसा लगता है कि यह पहले दो अधिभार ले रहा है और उन्हें रिपोर्ट करता है, बिना सही की जांच किए।

'ConsoleApplication1.Program.ComplexOverloadResolution (params string [])' और 'ConsoleApplication1.Program.ComplexOverloadResolution (स्ट्रिंग, ऑब्जेक्ट)'

Edit2: नई खोज। उपरोक्त तीनों में से किसी भी विधि को हटाने से दोनों के बीच कोई अस्पष्टता नहीं होगी। ऐसा लगता है कि संघर्ष केवल तभी प्रकट होता है जब आदेश की परवाह किए बिना तीन तरीके मौजूद हों।


लेकिन यह नहीं बताया गया है कि एक सदस्य को जोड़ने से दो तरीकों के बीच अस्पष्टता पैदा हो जाएगी जो पहले से मौजूद थे।
मैकके

अस्पष्टता आपके पहले और तीसरे तरीके के बीच होती है, लेकिन कंपाइलर रिपोर्ट क्यों करता है बाकी दो मेरे से परे हैं।
टॉमीस्लाव मार्कोवस्की

लेकिन अगर मैं दूसरी विधि निकालता हूं, तो मेरे पास कोई अस्पष्टता नहीं है, यह तीसरी विधि को सफलतापूर्वक कॉल करता है। इसलिए ऐसा नहीं लगता कि कंपाइलर में पहले और तीसरे तरीके के बीच अस्पष्टता है।
मैकके

मेरा संपादन देखें पागल संकलक।
टॉमीस्लाव मार्कोव्स्की

दरअसल, केवल दो तरीकों के किसी भी संयोजन से कोई अस्पष्टता पैदा नहीं होती है। यह बहुत अजीब है। EDIT2।
टॉमिस्लाव मार्कोवस्की

1
  1. अगर आप लिखेंगे

    var blah = new Overloaded();
    blah.ComplexOverloadResolution("Which wins?");

    या सिर्फ लिखें

    var blah = new Overloaded();
    blah.ComplexOverloadResolution();

    यह उसी विधि में , विधि में समाप्त हो जाएगा

    public void ComplexOverloadResolution(params string[] something

    यह कारण paramsकीवर्ड है जो इसे से बनाता है यह सबसे अच्छा मैच के लिए भी है जब कोई पैरामीटर निर्दिष्ट नहीं होता है

  2. यदि आप इस तरह से योर नई विधि को जोड़ने की कोशिश करते हैं

    public void ComplexOverloadResolution(string something)
    {
        Console.WriteLine("Added Later");
    }

    यह पूरी तरह से इस पद्धति को संकलित करेगा और कॉल करेगा क्योंकि यह एक पैरामीटर के साथ आपके कॉल के लिए एक आदर्श मैच हैstring । बहुत मजबूत तो params string[] something

  3. आपने दूसरी विधि घोषित की जैसे आपने किया

    public void ComplexOverloadResolution(string something, object something=null);

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

    var blah = new Overloaded();
    blah.ComplexOverloadResolution("Which wins?");

    यदि आप कॉल से स्ट्रिंग पैरामीटर हटाते हैं, तो वास्तव में, निम्न कोड की तरह, सब कुछ सही ढंग से संकलित होता है और पहले की तरह काम करता है

    var blah = new Overloaded();
    blah.ComplexOverloadResolution(); // will be ComplexOverloadResolution(params string[] something) function called here, like a best match.

सबसे पहले, आप दो कॉलिंग केस लिखते हैं जो समान हैं। तो निश्चित रूप से यह उसी पद्धति में जाएगा, या क्या आपका मतलब कुछ अलग लिखने का था?
मैकके

लेकिन फिर, अगर मैं आपके उत्तर के बाकी हिस्सों को सही ढंग से समझ रहा हूं, तो आप यह नहीं पढ़ रहे हैं कि कंपाइलर क्या कहता है, यह भ्रम है, पहले और दूसरे तरीकों के बीच, न कि नया तीसरा जो मैंने अभी जोड़ा है।
मैकके

आह, धन्यवाद। लेकिन फिर भी मैं अपनी दूसरी टिप्पणी में आपके द्वारा बताई गई समस्या को छोड़ देता हूं।
मैकके

अधिक स्पष्ट होने के लिए, आप कहते हैं "कंपाइलर, पहले तरीके और इस के बीच कुल भ्रम में कूदता है, बस एक जोड़ा।" लेकिन ऐसा नहीं है। यह अन्य दो तरीकों से भ्रम में कूद रहा है। परम विधि, और सामान्य विधि।
मैकके

@McKay: whell, यह भ्रम में कूद रहा है stateकि 3 कार्य दिए गए हैं, उनमें से एक या दो नहीं, सटीक होने के लिए। वास्तव में, किसी समस्या को हल करने के लिए उनमें से किसी पर टिप्पणी करना पर्याप्त है। उपलब्ध कार्यों के बीच सबसे अच्छा मेल यह है कि एक के साथ params, दूसरा वह है जो genericsपैरामीटर के साथ एक है , जब हम तीसरे को जोड़ते हैं तो यह setफ़ंक्शन में एक भ्रम पैदा करता है। मुझे लगता है, यह, सबसे अधिक संभावना है, संकलक द्वारा निर्मित स्पष्ट त्रुटि संदेश नहीं है।
तिगरान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.