2011-01-05 13 views
6

Possible Duplicate:
Why is Func<T> ambiguous with Func<IEnumerable<T>>?जेनेरिक्स, अधिभार संकल्प और प्रतिनिधियों (क्षमा करें, एक बेहतर शीर्षक नहीं मिल सकता है)

मैं जेनरिक के साथ एक बहुत अजीब अधिभार संकल्प मुद्दा ...

पर विचार करें निम्न विधियों देखा:

static void Foo<TSource>(TSource element, Func<TSource, int> selector) 
{ 
    "int".Dump(); 
} 

static void Foo<TSource>(TSource element, Func<TSource, double> selector) 
{ 
    "double".Dump(); 
} 

static T Identity<T>(T value) 
{ 
    return value; 
} 

(सी # 4, LINQPad में परीक्षण)

अगर मैं चयनकर्ता के रूप में एक लैम्ब्डा अभिव्यक्ति के साथ Foo कॉल करने के लिए कोशिश , सब कुछ ठीक काम करता है:

Foo(42, x => x); // prints "int" 

लेकिन अगर मैं Identity साथ x => x की जगह, संकलक 2 Foo भार के बीच तय नहीं कर सकते हैं:

Foo(42, Identity); 
// The call is ambiguous between the following methods or properties: 
// 'UserQuery.Foo<int>(int, System.Func<int,int>)' and 
// 'UserQuery.Foo<int>(int, System.Func<int,double>)' 

कैसे दूसरे अधिभार एक वैध उम्मीदवार हो सकता है? प्रकार निष्कर्ष सही ढंग से निर्धारित करता है कि TSourceint है, इसलिए Identity विधि के लिए T पैरामीटर int रूप में अच्छी तरह हो गया है, तो वापसी प्रकार int भी ... Identity एक Func<int,int> या एक Func<double,double>, लेकिन नहीं एक Func<int,double> हो सकता है हो गया है!

और यह और भी खराब हो जाता है!

Foo<int>(42, Identity<int>); // The call is ambiguous... 

कैसे यहाँ कोई अस्पष्टता नहीं हो सकता: यहां तक ​​कि अगर मैं सभी प्रकार पैरामीटर स्पष्ट रूप से निर्दिष्ट, मैं अभी भी एक ही त्रुटि मिलती है? जहां तक ​​मैं कह सकता हूं, Func<int,double> ले जाने वाला अधिभार कोई उम्मीदवार नहीं हो सकता है। मुझे लगता है कि स्पष्टीकरण विनिर्देशों में कहीं कहीं होना चाहिए, लेकिन मुझे प्रासंगिक बिट नहीं मिल रहा है ... या यह संकलक में एक बग हो सकता है, लेकिन मुझे लगता है कि यह असंभव है।

ध्यान दें कि यह अगर मैं स्पष्ट रूप से प्रतिनिधि बनाने के काम करता है:

Foo(42, new Func<int, int>(Identity)); // prints "int" 

तो, किसी को समझा सकता है यहाँ क्या हो रहा है? इसके अलावा, यह लैम्ब्डा के साथ क्यों काम करता है लेकिन विधि समूह के साथ नहीं?

+4

धैर्यपूर्वक एरिक लिपर्ट के लिए * उत्तर * पोस्ट करने का इंतजार कर रहा है। –

+0

सी # 3 के तहत क्या होता है? मुझे संदेह है कि जेनेरिक में टाइप वैरिएंस के साथ ऐसा कुछ हो सकता है। –

+0

@Anon, मैंने सी # 3 के साथ प्रयास नहीं किया, लेकिन मुझे नहीं लगता कि इसका भिन्नता के साथ कुछ भी नहीं है, क्योंकि भिन्नता मान प्रकार –

उत्तर

3

क्या यह केवल इसलिए नहीं है क्योंकि वापसी का प्रकार विधि के हस्ताक्षर का हिस्सा नहीं है?

तथ्य यह है कि Identity<T> विधि का तर्क प्रकार और वापसी प्रकार की गारंटी है, यह तय करने के लिए संकल्पकर्ता द्वारा खाते में नहीं लिया जाता है जब Foo<TSource> का अधिभार आवश्यक है। यदि वापसी का प्रकार नहीं माना जाता है तो Identity<int> समान रूप से परिवर्तनीय हो सकता है Func<int, int>, Func<int, double> या Func<int, anything>

+0

मुझे लगता है कि यह है। चलो देखते हैं कि एरिक इस बारे में क्या कहेंगे! – Lucero

+0

अच्छा बिंदु, मैं भूल गया कि वापसी का प्रकार हस्ताक्षर का हिस्सा नहीं था ... –

1

मुझे लगता है कि ल्यूकएच सही है। हालांकि, आपके प्रश्न के दूसरे भाग का जवाब देने के लिए: लैम्ब्डा के प्रतिनिधि के पास पहले से ही सभी प्रकार भर होंगे (उदा। Func<int, int> यदि TSourceint है), यही कारण है कि उस मामले में कोई अस्पष्टता नहीं है। यह एक फ़ंक्शन हस्ताक्षर की तरह नहीं है जहां रिटर्न प्रकार को अनदेखा किया जाता है।

+0

हाँ, मुझे लगता है कि यह सही स्पष्टीकरण है ... –

+1

बिलकुल नहीं। Lambdas अत्यधिक संदर्भ संवेदनशील हैं। वास्तव में, लैम्ब्डा संस्करण संदिग्ध है। http://ideone.com/IpUmb –

+0

@ बेन वोगेट, मुझे समझ में नहीं आता कि आपका क्या मतलब है ... यह कोड क्या दिखाना चाहिए? यह एक लैम्ब्डा के साथ ठीक काम करता है, इसलिए यह स्पष्ट होना चाहिए ... –

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