दिलचस्प पोस्ट
पहले शब्द के आकार को बढ़ाने के लिए सीएसएस क्यों करें: पहले और: छद्म तत्वों के बाद एक 'सामग्री' संपत्ति की आवश्यकता होती है? वैश्विक माउस ईवेंट हैंडलर गलत डेटा प्रकार इनपुट को कैसे संभालना है जावा में स्ट्रिंग की तुलना और स्ट्रिंग इंटर्निंग एक संग्रहीत कार्यविधि में "SET XACT_ABORT चालू" का उपयोग करने का क्या लाभ है? मूल प्रक्रिया को मार दिया जाता है जब बाल प्रक्रिया को मार डालो अपवाद प्राप्त करना "IllegalStateException: इस क्रिया को सवेव इनस्टेंसस्टेट के बाद नहीं किया जा सकता" पेंट कैसे काम करता है? डेलाइट सेविंग टाइम को ध्यान में रखते हुए दोहराए जाने वाले तारीखों को कैसे स्टोर करें क्या और कहाँ ढेर और ढेर हैं? किसी अन्य प्रोग्रामिंग भाषा में अनुवाद करना आसान बनाने के लिए मैं किस प्रकार के पैटर्न कोड पर लागू कर सकता हूं? जावास्क्रिप्ट बंद चेतावनी बॉक्स "New.target" क्या है? मैं फ़ंक्शन पॉइंटर्स के सरणी का उपयोग कैसे कर सकता हूं?

कंपाइलर संदिग्ध आवेश त्रुटि – गुंजाइश विधि और फ़ंक्शन के साथ विधि समूह <> या क्रिया

मेरे पास एक ऐसा परिदृश्य है जहां मैं फ़ंक्शन कॉल करने के लिए अनाम तरीकों (या लैम्ब्डा सिंटैक्स) के बजाय विधि समूह वाक्यविन्यास का उपयोग करना चाहता हूं।

फ़ंक्शन के दो ओवरलोड हैं, एक जो एक Action लेता है, दूसरे फ़ंक्शन को ले जाता है Func<string>

मैं अनाम तरीके (या लैम्ब्डा सिंटैक्स) का उपयोग करते हुए खुशी से दो अधिभारों को कॉल कर सकता हूं, लेकिन अगर मैं विधि समूह वाक्यविन्यास का उपयोग करता हूं, तो अस्पष्ट अभिवादन के एक संकलक त्रुटि प्राप्त करें I मैं स्पष्ट रूप से कास्टिंग या Action या Func<string> द्वारा काम कर सकता हूँ, लेकिन ऐसा नहीं लगता कि यह आवश्यक होना चाहिए।

क्या कोई यह स्पष्ट कर सकता है कि स्पष्ट कैस्ट क्यों आवश्यक होना चाहिए?

कोड नमूना नीचे

 class Program { static void Main(string[] args) { ClassWithSimpleMethods classWithSimpleMethods = new ClassWithSimpleMethods(); ClassWithDelegateMethods classWithDelegateMethods = new ClassWithDelegateMethods(); // These both compile (lambda syntax) classWithDelegateMethods.Method(() => classWithSimpleMethods.GetString()); classWithDelegateMethods.Method(() => classWithSimpleMethods.DoNothing()); // These also compile (method group with explicit cast) classWithDelegateMethods.Method((Func<string>)classWithSimpleMethods.GetString); classWithDelegateMethods.Method((Action)classWithSimpleMethods.DoNothing); // These both error with "Ambiguous invocation" (method group) classWithDelegateMethods.Method(classWithSimpleMethods.GetString); classWithDelegateMethods.Method(classWithSimpleMethods.DoNothing); } } class ClassWithDelegateMethods { public void Method(Func<string> func) { /* do something */ } public void Method(Action action) { /* do something */ } } class ClassWithSimpleMethods { public string GetString() { return ""; } public void DoNothing() { } } 

वेब के समाधान से एकत्रित समाधान "कंपाइलर संदिग्ध आवेश त्रुटि – गुंजाइश विधि और फ़ंक्शन के साथ विधि समूह <> या क्रिया"

सबसे पहले, मुझे यह बताएं कि जॉन का जवाब सही है। यह कल्पना के सबसे छोटे हिस्सेों में से एक है, जो उस पर डाइविंग के लिए सबसे पहले सिर पर है।

दूसरा, मुझे यह कहना है कि यह पंक्ति:

एक अंतर्निहित रूपांतरण एक विधि समूह से एक संगत प्रतिनिधि प्रकार में मौजूद है

(जोर दिया गया) गहरा भद्दा और दुर्भाग्यपूर्ण है। मैड के बारे में "संगत" शब्द को निकालने के बारे में बात करनी होगी I

यह भ्रामक और दुर्भाग्यपूर्ण कारण है, क्योंकि ऐसा लगता है कि यह खंड 15.2, "प्रतिनिधि अनुपालन" के लिए कॉल कर रहा है। धारा 15.2 ने तरीकों और प्रतिनिधि प्रकारों के बीच संगतता संबंध का वर्णन किया है, लेकिन यह विधि समूहों और प्रतिनिधि प्रकारों की परिवर्तनीयता का प्रश्न है, जो अलग है।

अब जब हमें रास्ता मिल गया है, हम कल्पना के खंड 6.6 के माध्यम से चल सकते हैं और देखें कि हमें क्या मिलता है।

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

 class Program { delegate void D1(); delegate string D2(); static string X() { return null; } static void Y(D1 d1) {} static void Y(D2 d2) {} static void Main() { Y(X); } } 

तो चलो लाइन के माध्यम से इसे लाइन के माध्यम से चलते हैं

एक अंतर्निहित रूपांतरण एक विधि समूह से एक संगत प्रतिनिधि प्रकार में मौजूद है।

मैंने पहले से ही चर्चा की है कि "संगत" शब्द यहाँ दुर्भाग्यपूर्ण है। आगे बढ़ते रहना। वाई (एक्स) पर अधिभार संकल्प करते समय हम सोच रहे हैं, विधि समूह X को डी 1 में बदलना है? क्या यह डी 2 में बदलता है?

एक प्रतिनिधि प्रकार डी और एक अभिव्यक्ति ई को देखते हुए जिसे एक विधि समूह के रूप में वर्गीकृत किया गया है, ई से डी में एक अंतर्निहित रूपांतरण मौजूद है यदि ई में कम से कम एक विधि शामिल है जो […] पैरामीटर के उपयोग द्वारा निर्मित तर्क सूची में लागू है प्रकार और डी के संशोधक, जैसा कि निम्नलिखित में वर्णित है।

अब तक सब ठीक है। एक्स में ऐसी कोई विधि हो सकती है जो D1 या D2 की तर्क सूचियों पर लागू होती है

एक समूह समूह ई से एक रूपांतरण प्रकार डी को रूपांतरण के संकलन-समय पर आवेदन निम्न में वर्णित है।

यह रेखा वास्तव में कुछ दिलचस्प नहीं कहती

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

यह रेखा आकर्षक है इसका मतलब है कि वहाँ मौजूद निहित रूपांतरण होते हैं, लेकिन जो त्रुटियों में बदल जाते हैं! यह सी # का एक विचित्र नियम है एक पल को हटाना, यहां एक उदाहरण है:

 void Q(Expression<Func<string>> f){} string M(int x) { ... } ... int y = 123; Q(()=>M(y++)); 

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

वैसे भी, यह इस तरह के विचित्र नियम का एक और उदाहरण है ओवरलोड संकल्प के प्रयोजनों के लिए एक रूपांतरण मौजूद हो सकता है, लेकिन वास्तव में इसका उपयोग करने के लिए एक त्रुटि हो सकती है। हालांकि वास्तव में, यह वास्तव में स्थिति नहीं है, जहां हम यहां हैं।

आगे बढ़ते रहना:

एक ही विधि एम, ई (ए) के एक विधि के आह्वान के अनुरूप चुना जाता है […] तर्क सूची अभिव्यक्तियों की एक सूची है, प्रत्येक को वेरिएबल […] के रूप में वर्गीकृत किया गया है, औपचारिक रूप से संबंधित पैरामीटर में डी की रैपरमेटर-सूची

ठीक। इसलिए हम डी 1 के संबंध में एक्स पर अधिभार संकल्प करते हैं। डी 1 की औपचारिक पैरामीटर सूची खाली है, इसलिए हम एक्स () और आनन्द पर ओवरलोड रिज़ॉल्यूशन करते हैं, हमें एक स्ट्रिंग एक्स () मिलती है जो काम करती है इसी तरह, डी 2 की औपचारिक पैरामीटर सूची रिक्त है। दोबारा, हम पाते हैं कि "स्ट्रिंग एक्स ()" एक विधि है जो यहां भी काम करती है

सिद्धांत यहाँ है कि विधि समूह परिवर्तनीयता का निर्धारण करने के लिए अधिभार संकल्प के माध्यम से एक विधि समूह से विधि का चयन करना आवश्यक है , और ओवरलोड संकल्प में वापसी प्रकार पर विचार नहीं होता है

यदि एल्गोरिथ्म […] एक त्रुटि उत्पन्न करता है, तो एक संकलन-समय त्रुटि होती है अन्यथा एल्गोरिथ्म डी के रूप में समान पैरामीटर वाले एक एकल सर्वश्रेष्ठ विधि का उत्पादन करता है और रूपांतरण को मौजूद माना जाता है।

विधि समूह X में केवल एक ही तरीका है, इसलिए यह सबसे अच्छा होना चाहिए। हमने सफलतापूर्वक साबित किया है कि एक्स से डी 1 और एक्स से डी 2 तक कोई रूपांतरण मौजूद है।

अब, क्या यह रेखा प्रासंगिक है?

चयनित विधि M को प्रतिनिधि प्रकार D के साथ संगत होना चाहिए, या अन्यथा, एक संकलन-समय त्रुटि उत्पन्न होती है।

दरअसल, नहीं, इस कार्यक्रम में नहीं। हम इस रेखा को सक्रिय करने के लिए कभी भी प्राप्त नहीं करते हैं क्योंकि, याद रखें, हम यहाँ क्या कर रहे हैं वाई (एक्स) पर अधिभार संकल्प करने की कोशिश कर रहे हैं। हमारे पास दो उम्मीदवार वाई (डी 1) और वाई (डी 2) हैं दोनों लागू होते हैं। कौन सा बेहतर है ? विवरण में कहीं नहीं, हम इन दो संभावित रूपांतरणों के बीच विकृति का वर्णन करते हैं

अब, कोई निश्चित रूप से तर्क दे सकता है कि एक वैध रूपांतरण एक से बेहतर है जो त्रुटि उत्पन्न करता है वह तब प्रभावी रूप से कह रहा होगा, इस मामले में, उस अधिभार संकल्प में वापसी के प्रकार पर विचार किया जाता है, जो कि हम से बचना चाहते हैं तो सवाल यह है कि कौन सा सिद्धांत बेहतर होता है: (1) अपरिवर्तनीयता को बनाए रखना है कि अधिभार के रिज़ॉल्यूशन में वापसी के प्रकार पर विचार नहीं होता है, या (2) हम जानते हैं कि हम उस रूपांतरण को चुनने का प्रयास करेंगे जो हमें पता चलेगा?

यह एक फैसले कॉल है लैम्ब्दास के साथ, हम इस तरह के रूपांतरणों में वापसी प्रकार पर विचार करते हैं, खंड 7.4.3.3 में:

ई एक गुमनाम कार्य है, टी 1 और टी 2 प्रतिनिधि प्रकार या अभिव्यक्ति के पेड़ प्रकार समान पैरामीटर सूचियों के साथ हैं, ये पैरामीटर सूची के संदर्भ में एक अनुमानित रिटर्न टाइप एक्स मौजूद है, और निम्न में से एक के पास है:

  • टी 1 में रिटर्न टाइप Y1 है, और टी 2 में रिटर्न टाइप Y2 है, और एक्स से वाई 1 में रूपांतरण X से Y2 के रूपांतरण से बेहतर है

  • टी 1 में रिटर्न टाइप वाई है, और टी 2 शून्य वापसी है

यह दुर्भाग्यपूर्ण है कि इस संबंध में विधि समूह रूपांतरण और लैम्ब्डा रूपांतरण असंगत हैं। हालांकि, मैं इसके साथ रह सकता हूं।

वैसे भी, हमारे पास कोई "बेरहमी" नियम नहीं है यह निर्धारित करने के लिए कि कौन से रूपांतरण बेहतर है, एक्स से डी 1 या एक्स से डी 2 तक इसलिए हम वाई (एक्स) के संकल्प पर एक अस्पष्टता त्रुटि देते हैं।

संपादित करें: मुझे लगता है कि मुझे यह मिल गया है।

ज़िंगलोन कहते हैं, क्योंकि यह गेटस्ट्रिंग से Action तक एक अन्तर्निहित रूपांतरण है, हालांकि संकलन-समय का आवेदन विफल हो जाएगा। यहां अनुभाग 6.6 का परिचय दिया गया है, कुछ जोर (मेरा) के साथ:

एक अंतर्निहित रूपांतरण (§6.1) एक विधि समूह (§7.1) से एक संगत प्रतिनिधि प्रकार में मौजूद है। एक प्रतिनिधि प्रकार डी और एक अभिव्यक्ति ई को एक विधि समूह के रूप में वर्गीकृत किया गया है, ई से डी में एक अंतर्निहित रूपांतरण मौजूद है यदि ई में कम से कम एक विधि है जो उसके सामान्य रूप (§7.4.3.1) में एक तर्कसूची के निर्माण के लिए लागू होती है पैरामीटर प्रकारों और डी के संशोधक का उपयोग करके , जैसा कि निम्नलिखित में वर्णित है।

अब, मुझे पहले वाक्य से भ्रमित हो रहा था – जो एक संगत प्रतिनिधि प्रकार में एक रूपांतरण के बारे में बात करता है। Action GetString विधि समूह में किसी भी विधि के लिए एक संगत प्रतिनिधि नहीं है, लेकिन GetString() विधि अपने सामान्य रूप में पैरामीटर प्रकारों और डी के संशोधक के उपयोग द्वारा निर्मित तर्क सूची में लागू होती है। नोट करें कि यह बात नहीं करता है डी के रिटर्न प्रकार के बारे में। यही कारण है कि यह उलझन में हो रहा है … क्योंकि यह रूपांतरण के दौरान केवल GetString() की प्रतिनिधि संगतता की जांच करेगा, इसके अस्तित्व की जाँच न करे

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

 using System; class Program { static void ActionMethod(Action action) {} static void IntMethod(int x) {} static string GetString() { return ""; } static void Main(string[] args) { IntMethod(GetString); ActionMethod(GetString); } } 

Main कंपाइल में विधि अभिविन्यास अभिव्यक्ति में से कोई भी नहीं, लेकिन त्रुटि संदेश अलग हैं। यहां IntMethod(GetString) के लिए एक है:

Test.cs (12,9): त्रुटि CS1502: 'Program.IntMethod (int)' के लिए सबसे अच्छा अतिभारित विधि मिलान में कुछ अमान्य तर्क हैं

दूसरे शब्दों में, स्पेस के अनुभाग 7.4.3.1 को कोई भी लागू फ़ंक्शन सदस्य नहीं मिल सकता है।

अब ActionMethod(GetString) के लिए त्रुटि है:

Test.cs (13,22): त्रुटि CS0407: 'स्ट्रिंग प्रोग्राम। GetString ()' में गलत वापसी प्रकार है

इस बार उसने इसे बुलाए जाने वाला तरीका तैयार किया है – लेकिन आवश्यक रूपांतरण करने में विफल रहा है। दुर्भाग्य से मैं उस नमूने का थोड़ा पता नहीं लगा सकता जहां अंतिम जांच की जाती है – ऐसा लगता है कि यह 7.5.5.1 में हो सकता है, लेकिन मुझे बिल्कुल नहीं पता है


इस बिट को छोड़कर पुराने उत्तर हटा दिए गए – क्योंकि मुझे उम्मीद है कि एरिक इस प्रश्न के "क्यों" पर प्रकाश डाल सकता है …

अभी भी तलाश … अगर हम "एरिक लिपर्ट" तीन बार कहते हैं, तो क्या आपको लगता है कि हम एक विज़िट प्राप्त करेंगे (और इस प्रकार एक उत्तर)?

Func और Action साथ ओवरलोडिंग समान है (क्योंकि दोनों ही प्रतिनिधि हैं)

 string Function() // Func<string> { } void Function() // Action { } 

यदि आप ध्यान देते हैं, तो संकलक को यह नहीं पता कि किसको कॉल करना है क्योंकि वे केवल वापसी प्रकार से भिन्न होते हैं।

Func<string> और Action<string> (स्पष्ट रूप से Action और ClassWithDelegateMethods लिए बहुत भिन्न) Func<string> के ClassWithDelegateMethods से ClassWithDelegateMethods में अस्पष्टता को हटा दिया गया है।

अस्पष्टता भी Action और Func<int> बीच होती है

मुझे इसके साथ अस्पष्टता त्रुटि भी मिलती है:

 class Program { static void Main(string[] args) { ClassWithSimpleMethods classWithSimpleMethods = new ClassWithSimpleMethods(); ClassWithDelegateMethods classWithDelegateMethods = new ClassWithDelegateMethods(); classWithDelegateMethods.Method(classWithSimpleMethods.GetOne); } } class ClassWithDelegateMethods { public void Method(Func<int> func) { /* do something */ } public void Method(Func<string> func) { /* do something */ } } class ClassWithSimpleMethods { public string GetString() { return ""; } public int GetOne() { return 1; } } 

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

 class Program { static void Main(string[] args) { ClassWithSimpleMethods classWithSimpleMethods = new ClassWithSimpleMethods(); ClassWithDelegateMethods classWithDelegateMethods = new ClassWithDelegateMethods(); //The call is ambiguous between the following methods or properties: //'test.ClassWithDelegateMethods.Method(System.Func<int,int>)' //and 'test.ClassWithDelegateMethods.Method(test.ClassWithDelegateMethods.aDelegate)' classWithDelegateMethods.Method(classWithSimpleMethods.GetX); } } class ClassWithDelegateMethods { public delegate string aDelegate(int x); public void Method(Func<int> func) { /* do something */ } public void Method(Func<string> func) { /* do something */ } public void Method(Func<int, int> func) { /* do something */ } public void Method(Func<string, string> func) { /* do something */ } public void Method(aDelegate ad) { } } class ClassWithSimpleMethods { public string GetString() { return ""; } public int GetOne() { return 1; } public string GetX(int x) { return x.ToString(); } }