2015-09-17 20 views
17

साथ निष्कर्ष निम्न उदाहरण पर विचार करें।"दो स्तर" सामान्य विधि तर्क प्रतिनिधि

मुझे आश्चर्य है कि मैं <string> सामान्य तर्क क्यों नहीं हटा सकता? मुझे एक त्रुटि मिलती है कि इसे उपयोग से अनुमानित नहीं किया जा सकता है।

मैं समझता हूं कि ऐसा अनुमान संकलक के लिए चुनौतीपूर्ण हो सकता है, लेकिन फिर भी ऐसा लगता है।

मुझे इस व्यवहार की व्याख्या करना है।

संपादित जॉन हैना के जवाब का जवाब दे:

फिर क्यों इस काम करता है?

class Test 
{ 
    public void Fun<T1, T2>(T1 a, Func<T1, T2> f) 
    { 
    } 

    public string Fun2(int test) 
    { 
     return test.ToString(); 
    } 

    public Test() 
    { 
     Fun(0, Fun2); 
    } 
} 

यहाँ मैं T1 a साथ केवल एक पैरामीटर के लिए बाध्य है, लेकिन T2 इसी तरह मुश्किल हो रहा है।

+0

अपने संपादन को पुनः पढ़ें, अब आपने 'Fun (0, Fun2);' कॉल के माध्यम से संकलक की आपूर्ति की है। कंपाइलर अब जानता है कि इसे 'Fun2' विधि समूह' से एक विधि की आवश्यकता है, जिसमें 'T1' प्रकार है, इस मामले में' int'। यह इसे एक विधि तक सीमित करता है और इसलिए यह अनुमान लगा सकता है कि किस का उपयोग करना है। –

+0

लेकिन पहली जगह में एक Fun2 है, इसलिए यह वास्तव में कुछ भी संकीर्ण नहीं करता है। –

+0

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

उत्तर

13

यह प्रकार का अनुमान नहीं लगा सकता है, क्योंकि इस प्रकार को यहां परिभाषित नहीं किया गया है।

Fun2Func<string, string> नहीं है, हालांकि ऐसा कुछ है जिसे Func<string, string> पर असाइन किया जा सकता है।

तो अगर आप का उपयोग करें:

public Test() 
{ 
    Func<string, string> del = Fun2; 
    Fun(del); 
} 

या:

public Test() 
{ 
    Fun((Func<string, string>)Fun2); 
} 

तो आप स्पष्ट रूप से Fun2 से एक Func<string, string> बना रहे हैं तथा सामान्य प्रकार अनुमान के हिसाब से काम करता है।

इसके विपरीत, जब आप ऐसा करेंगे:

public Test() 
{ 
    Fun<string>(Fun2); 
} 

तब भार के Fun<string> के सेट केवल एक ही है कि एक Func<string, string> स्वीकार करता है और संकलक अनुमान लगा सकते हैं कि आप इस तरह के रूप Fun2 उपयोग करना चाहते हैं।

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

(यह न केवल थे .NET 1.0 में है कि विचार के लायक है प्रतिनिधियों नहीं सामान्य-ताकि आप -लेकिन यह भी जरूरी हो गया था एक निर्माता Fun(new MyDelegate(Fun2)) साथ वस्तु बनाने के लिए delgate string MyDelegate(string test) परिभाषित करने के लिए था। वाक्य रचना उपयोग करने के लिए बदल गया है प्रतिनिधियों के कई तरीकों से आसान है, लेकिन Fun2 के Func<string, string> के अंतर्निहित उपयोग अभी भी दृश्यों के पीछे एक प्रतिनिधि वस्तु का निर्माण है)।

फिर यह क्यों काम करता है?

class Test 
{ 
    public void Fun<T1, T2>(T1 a, Func<T1, T2> f) 
    { 
    } 

    public string Fun2(int test) 
    { 
     return test.ToString(); 
    } 

    public Test() 
    { 
     Fun(0, Fun2); 
    } 
} 

क्योंकि तब यह अनुमान लगा सकते हैं, क्रम में:

  1. T1int है।
  2. Fun2 को T2 के लिए Func<int, T2> पर असाइन किया जा रहा है।
  3. Fun2Func<int, T2> को T2string पर असाइन किया जा सकता है। इसलिए T2 स्ट्रिंग है।

विशेष रूप से, Func के वापसी प्रकार को आपके द्वारा तर्क प्रकार होने के बाद एक फ़ंक्शन से अनुमानित किया जा सकता है। यह भी ठीक है (और संकलक के हिस्से पर प्रयास के लायक है) क्योंकि यह लिंक के Select में महत्वपूर्ण है। इससे संबंधित मामला सामने आता है, तथ्य यह है कि x.Select(i => i.ToString()) के साथ हमारे पास यह जानने के लिए पर्याप्त जानकारी नहीं है कि लैम्ब्डा को क्या डाला जाता है। एक बार जब हम जानते हैं कि xIEnumerable<T> या IQueryable<T> हम जानते हैं कि हमारे पास Func<T, ?> या Expression<Func<T, ?>> है और शेष को वहां से अनुमानित किया जा सकता है।

यह भी ध्यान देने योग्य है कि रिटर्न प्रकार को कम करना एक अस्पष्टता के अधीन नहीं है जो अन्य प्रकारों को कम करता है। इस बात पर विचार करें कि क्या हमारे पास Fun2 (वह एक है जो string और एक ही कक्षा में int) लेता है। यह मान्य सी # ओवरलोडिंग है, लेकिन Func<T, string> के प्रकार की कटौती करता है कि Fun2 असंभव में डाला जा सकता है; दोनों मान्य हैं।

हालांकि, जबकि .NET रिटर्न प्रकार पर ओवरलोडिंग की अनुमति देता है, सी # नहीं करता है। इसलिए T के प्रकार को निर्धारित करने के बाद एक विधि (या लैम्बडा) से बनाए गए Func<T, TResult> के रिटर्न प्रकार पर कोई मान्य सी # प्रोग्राम संदिग्ध नहीं हो सकता है। उस सापेक्ष आसानी, महान उपयोगिता के साथ मिलकर, यह कुछ बनाता है जो संकलक हमारे लिए अनुमान लगाने के लिए अच्छा है।

+0

बेशक मेरा संपादन 'चयन' से प्रेरित था।क्या आपका मतलब है कि इस तरह के मामले में रिटर्न टाइप अनुमान लागू करना आसान था? ओवरलोड के साथ समस्याओं से बचने के लिए? // संपादित करें, यही वह है जो आपने लिखा है, हमारे पास दौड़ थी ;-) मुझे यह देखना अच्छा लगेगा कि ईसीएमए में इसे खोदना होगा। –

+0

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

+0

क्यों यह इसका अनुमान नहीं लगाता है? –

3

आप string को Fun2 से अनुमानित करने के लिए कंपाइलर चाहते हैं, जो सी # कंपाइलर के लिए बहुत अधिक पूछताछ है। ऐसा इसलिए है क्योंकि Test में संदर्भित होने पर, यह एक प्रतिनिधि समूह के रूप में Fun2 को एक प्रतिनिधि समूह के रूप में देखता है।

आप पैरामीटर Fun2 की जरूरत में गुजरती हैं और Fun से यह आह्वान करने के लिए कोड बदल दें तो जरूरत, चला जाता है के रूप में आप अब एक string पैरामीटर, प्रकार अनुमान लगाया जा करने की अनुमति:

class Test 
{ 
    public void Fun<T>(Func<T, T> f, T x) 
    { 
     f(x); 
    } 

    public string Fun2(string test) 
    { 
     return test; 
    } 

    public Test() 
    { 
     Fun(Fun2, ""); 
    } 
} 

T1 प्रकार की आपूर्ति करके, प्रश्न के अपने संपादित संस्करण का उत्तर देने के लिए अब आपने संकलक की आपूर्ति की है - Fun(0, Fun2); कॉल - अतिरिक्त जानकारी के माध्यम से। अब यह जानता है कि Fun2 विधि समूह से T1 पैरामीटर है, इस मामले में int में यह एक विधि की आवश्यकता है। यह इसे एक विधि तक सीमित करता है और इसलिए यह अनुमान लगा सकता है कि किस का उपयोग करना है।

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