2009-06-19 14 views
28

एक्सटेंशन तरीकों प्रतिनिधियों कि एक वस्तु पर उनके उपयोग से मेल करने के लिए आवंटित किया जा सकता है, इस तरह:मूल्य प्रकारों पर परिभाषित एक्सटेंशन विधियों का उपयोग प्रतिनिधियों को बनाने के लिए नहीं किया जा सकता है - क्यों नहीं?

static class FunnyExtension { 
    public static string Double(this string str) { return str + str; } 
    public static int Double(this int num) { return num + num; } 
} 


Func<string> aaMaker = "a".Double; 
Func<string, string> doubler = FunnyExtension.Double; 

Console.WriteLine(aaMaker());  //Prints "aa" 
Console.WriteLine(doubler("b")); //Prints "bb" 

प्रकार वे का विस्तार कर रहे एक मान प्रकार है, तो यह काम नहीं करेगा:

Func<int> eightMaker = 4.Double; //Error CS1113: Extension methods 'FunnyExtension.Double(int)' defined on value type 'int' cannot be used to create delegates 
Func<int, int> intDoubler = FunnyExtension.Double; //Works 

इससे

त्रुटि CS1113: विस्तार तरीकों 'FunnyExtension.Double (int)' मान प्रकार 'int' पर परिभाषित प्रतिनिधियों बनाने के लिए इस्तेमाल नहीं किया जा सकता।

वे क्यों नहीं कर सकते?

+0

क्या आप वाकई CS1113 नहीं हैं? –

+0

यह है; तय की। धन्यवाद – SLaks

उत्तर

18

मेरे अन्य जवाब के जवाब में, एरिक स्मिथ सही ढंग से नोट:

"... क्योंकि यह परोक्ष रिसीवर प्रकार पैरामीटर मुक्केबाजी की आवश्यकता होगी ..."। वैसे भी क्या होता है, अगर आप ऐसा कुछ करते हैं: Func f = 5.ToString; जो पूरी तरह से कानूनी है।

इस बारे में सोचने से मुझे एक नया जवाब मिल गया है। इसे आकार के लिए आज़माएं:

सीआईएल स्तर पर, "प्रबंधित सूचक" टाइप करें (टाइप &) एक रिसीवर पैरामीटर के रूप में, स्ट्रक्चर पर सामान्य "उदाहरण" विधियां लेते हैं। यह आवश्यक है ताकि structs पर उदाहरण विधियां संरचना के क्षेत्रों को असाइन कर सकें। Partition II, Section 13.3 देखें।

इसी तरह, कक्षाओं पर उदाहरण विधियों को "ऑब्जेक्ट रेफरेंस" (O टाइप करें) एक रिसीवर पैरामीटर के रूप में लें (अंतर यह है कि यह प्रबंधित ढेर के लिए एक सूचक है, और जीसी के लिए ट्रैक किया जाना चाहिए)।

चूंकि दोनों सीआईएल & एस और O एस पॉइंटर्स द्वारा कार्यान्वित (और हैं) हो सकते हैं, सब कुछ प्रतिनिधि कार्यान्वयन के लिए हंकी-डोरी है। इस बात पर ध्यान दिए बिना कि कोई प्रतिनिधि एक स्थिर विधि, एक क्लास इंस्टेंस विधि या एक स्ट्रक्चर इवेंट विधि कैप्चर करता है, उसे केवल फ़ंक्शन के पहले तर्क में पॉइंटर को _target पर पास करना होगा।

लेकिन परिदृश्य हम खंडहरों पर चर्चा कर रहे हैं। पहले तर्क के रूप में int को लेने वाली एक स्थैतिक विस्तार विधि के लिए int32 (विभाजन III, खंड 1.1.1 देखें) के सीआईएल तर्क की आवश्यकता होती है। यहां वह जगह है जहां चीजें रेल से निकलती हैं। मुझे कोई कारण नहीं दिख रहा है कि यह संभवतः प्रतिनिधियों के कार्यान्वयन के लिए क्यों नहीं हो सकता है कि यह हो रहा है (उदाहरण के लिए, विधिप्राप्ति से जुड़े मेटाडेटा का निरीक्षण करके) और एक थंक उत्सर्जित करें जो अनबॉक्स होगा _target और इसे पहले तर्क के रूप में पास करें, लेकिन प्रतिनिधियों के लिए स्ट्रक्चर पर शास्त्रीय उदाहरण विधियों के लिए इसकी आवश्यकता नहीं है, क्योंकि वे किसी भी सूचक को की उम्मीद करते हैं और प्रकट नहीं होते हैं (मेरे पहले गलत जवाब में उदाहरण के आधार पर) परिपालित करते रहें। स्पष्ट रूप से प्रश्न में विशिष्ट मान प्रकार आवश्यक थंक की सटीक प्रकृति को नियंत्रित करेगा।

जब तक मैं कार्यान्वयन के लिए और अधिक मौलिक बाधा नहीं खो रहा हूं (मैं कल्पना कर सकता हूं कि यह सत्यापनकर्ता के लिए समस्याएं पैदा करेगा, उदाहरण के लिए), ऐसा लगता है कि इस मामले का समर्थन करने के लिए रनटाइम को विस्तारित करने के लिए उचित मामला बनाया जा सकता है, लेकिन सभी संकेत इस समय की ओर इशारा कर रहे हैं कि रनटाइम की सीमा है और सी # कंपाइलर प्रति से नहीं है।

+5

डौग, आपका विश्लेषण उत्कृष्ट है। जैसा कि हमने ईमेल द्वारा चर्चा की, मेरे कॉलेग्यू श्रीकर ने अपने ब्लॉग http://blogs.msdn.com/sreekarc/archive/2009/06/25/why-can-t-extension-methods-on-value- में कुछ नोट्स किए हैं। टाइप-बी-curried.aspx और मैंने कुछ नोट्स दिए हैं कि यह समस्या मेरे ब्लॉग में "प्रतिबिंब करीकरण" के साथ कैसे दिखाई देती है। http://blogs.msdn.com/ericlippert/archive/2009/06/25/mmm-curry.aspx –

+1

इस में खोदने के लिए समय निकालने के लिए एरिक और श्रीकर के लिए बहुत धन्यवाद और इसे सभी के लिए समझाएं! –

+1

ब्लॉग पोस्ट [ओपन डिलीगेट्स बनाम क्लोज़ेड डेलीगेट्स] (http://blog.slaks.net/2011/06/open-delegates-vs-closed-delegates.html) भी देखें जो पूछताछकर्ता द्वारा लिखी गई थी। लक्स) बाद में। –

2

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

मूल

क्योंकि यह परोक्ष की आवश्यकता होगी मान प्रकार रिसीवर पैरामीटर मुक्केबाजी (क्योंकि System.Delegate प्रकार है जो रिसीवर पैरामीटर रखती में _target फ़ील्ड प्रकार System.Object की है) है, जो ले जा सकता है अगर आप इसकी अपेक्षा नहीं कर रहे थे तो कुछ अजीब अलियासिंग व्यवहार के लिए।

संपादित

वहाँ कुछ और यहाँ पर जा रहा है। मैंने इस नमूना कार्यक्रम को चलाया:

class Program 
{ 
    public static int Combine(int a, int b) 
    { 
     return a + b; 
    } 

    static void Main(string[] args) 
    { 
     var combineMethod = typeof(Program).GetMethod("Combine"); 
     var add4 = Delegate.CreateDelegate(
           typeof(Converter<int, int>), 
           4, 
           combineMethod) as Converter<int, int>; 

     for (int i = 0; i < 10; i++) 
     { 
      Console.WriteLine(add4(i)); 
     } 
     Console.ReadLine(); 
    } 
} 

और एक ArgumentException मिला: "लक्ष्य विधि को बाध्य करने में त्रुटि।" CreateDelegate करने के लिए कॉल पर। मुझे यकीन नहीं है क्यों, और क्योंकि प्रासंगिक विधि internalcall विधि है, परावर्तक बहुत मदद नहीं करता है। documentation for CreateDelegate भी बहुत मदद नहीं थी। मुझे यकीन है कि मुक्केबाज़ी रिसीवर के साथ इसका कुछ संबंध है, शायद रोटर स्रोत के ज्ञान वाले किसी व्यक्ति को यह समझाने में मदद मिल सकती है कि क्यों?

+0

किस प्रकार का अजीब अलियासिंग व्यवहार? –

+0

क्या एलियासिंग व्यवहार यह हो सकता है कि आप उम्मीद नहीं करेंगे? चूंकि विस्तार विधि पहले से ही नियमित पैरामीटर के रूप में मान प्रकार लेती है, इसलिए यह मानने का कोई कारण नहीं होगा कि यह एक प्रतिलिपि नहीं बनायेगा। – SLaks

+0

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

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