2015-06-17 9 views
9

यह क्या कहा जाता है जब एक विधि जो लैम्ब्डा अभिव्यक्ति को पैरामीटर के रूप में लेती है, जैसे Enumerable.Where, वास्तव में अभिव्यक्ति में एक चर या विधि पैरामीटर घोषित किए बिना बुलाया जाता है?सी # लैम्ब्डा अभिव्यक्तियों के बिना परिवर्तनीय/पैरामीटर घोषणा?

उदाहरण के लिए, मैं इस लैम्ब्डा अभिव्यक्ति वाक्य रचना से परिचित हूँ:

public string GetDigits(string input) 
{ 
    return new String(input.Where(i => Char.IsDigit(i)).ToArray()); 
} 

हालांकि, मैं find out आश्चर्य हुआ है कि इस के रूप में भी लिखा जा सकता है: क्या में हो रहा है

public string GetDigits(string input) 
{ 
    return new String(input.Where(Char.IsDigit).ToArray()); 
} 

वह दूसरा स्निपेट, जहां Char.IsDigit() विधि (स्पष्ट रूप से) एक अंतर्निहित पैरामीटर के साथ बुलाया जा रहा है? इस वाक्यविन्यास को क्या कहा जाता है?

+0

रीशेर्पर लागू होने पर सरलीकृत वाक्यविन्यास का भी सुझाव देता है। –

+0

यह अब तक एक लैम्ब्डा-अभिव्यक्ति नहीं है, लेकिन एक प्रतिनिधि को किसी अन्य विधि के लिए तर्क के रूप में पास कर रहा है। –

+1

आप एक * विधि समूह * देख रहे हैं। –

उत्तर

16

तरीके पैरामीटर के रूप में lambdas स्वीकार नहीं करते हैं। वे पैरामीटर के रूप में प्रतिनिधि स्वीकार करते हैं।एक लैम्ब्डा एक प्रतिनिधि बनाने का सिर्फ एक तरीका है।

एक और तरीका एक विधि समूह की आपूर्ति कर रहा है, जैसा कि आपके दूसरे उदाहरण में किया गया है, जिसे एक प्रतिनिधि में परिवर्तित किया जा सकता है।

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

Func<char, bool> predicate = delegate(char c) { return Char.IsDigit(c); }; 

फिर भी एक और तरीका एक प्रतिनिधि Delegate.CreateDelegate का उपयोग कर बनाने के लिए किया जाएगा। (यह ऐसा कुछ नहीं है जो आप अक्सर देखते हैं।)

एक अंतिम तरीका यह है कि एक प्रतिनिधि चर है जिसे आप कहीं और से प्राप्त करते हैं। (किसी और यही कारण है कि कहीं न कहीं प्रतिनिधि इन अन्य विकल्पों में से एक का उपयोग कर बनाया होगा।)

क्या है कि दूसरी टुकड़ा है, जहां (जाहिरा तौर पर) एक अंतर्निहित पैरामीटर के साथ बुलाया जा रहा है Char.IsDigit() विधि में हो रहा है? इस वाक्यविन्यास को क्या कहा जाता है?

यह नहीं कहा जा रहा है। यह पूरी बात है। हम एक प्रतिनिधि बनाने की कोशिश कर रहे हैं। एक प्रतिनिधि एक वस्तु है जो किसी विधि को लागू करने के तरीके का ट्रैक रखता है, और एक वस्तु जिसे इसे लागू किया जाना चाहिए। फिर आप प्रतिनिधि को आमंत्रित कर सकते हैं और यह उस विधि को कॉल करेगा जिसका उपयोग इसे बनाने के लिए किया गया था। तो यहां आप IsDigit पर कॉल कर रहे हैं, आप एक प्रतिनिधि बना रहे हैं जो IsDigit विधि पर इंगित कर रहा है, और जब भी उस प्रतिनिधि को बुलाया जाता है तो उसे कॉल किया जाएगा।

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

+0

* जब आप लैम्ब्डा का उपयोग करते हैं तो आप एक नई कक्षा बना रहे हैं * केवल अगर लैम्ब्डा एक आवृत्ति चर या फ़ील्ड पर बंद हो जाता है, अन्यथा इसे आक्रमणकारी कक्षा के अंदर कैश किया जाएगा। –

+0

क्या गैर-स्थैतिक विधि का उपयोग प्रतिनिधि के रूप में करना संभव है जो सीधे पहुंच योग्य नहीं है? तो यदि 'Char.IsDigit' स्थिर नहीं था, तो क्या आप इसे प्रतिनिधि के रूप में उपयोग कर सकते हैं? –

+1

@TimSchmelter आप एक प्रतिनिधि बनाने के लिए एक गैर स्थैतिक विधि के विधि समूह का उपयोग कर सकते हैं, हां। एक विधि समूह के लिए परिवर्तनीय होने के लिए एक विधि समूह के लिए एकमात्र आवश्यकता है, जो कि प्रतिनिधि समूह के हस्ताक्षर से मेल खाने वाले विधि समूह का एक अद्वितीय सर्वश्रेष्ठ अधिभार है। अगर किसी भी ओवरलोड में सही हस्ताक्षर नहीं है, या अस्पष्टता है जिसमें "सर्वश्रेष्ठ" है, तो यह त्रुटि होगी। – Servy

8

क्योंकि संकलक परोक्ष वह एक ही विधि है कि उम्मीद हस्ताक्षर से मेल खाता है एक प्रतिनिधि एक भी char इनपुट के रूप में ले रही है और एक bool लौट पाता है, इस मामले में एक प्रतिनिधि को विधि समूह डाली जाएगी।

10

Enumerable.Where के हस्ताक्षर है:

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, bool> predicate 
) 

यह:

Func<char, bool> temp = i => Char.IsDigit(i); 
input.Where(temp); 

तो यह एक पैरामीटर i कि कॉल के साथ एक गुमनाम समारोह बनाता है:

input.Where(i => Char.IsDigit(i)) 

लेखन के बराबर है Char.IsDigit

यह:

input.Where(Char.IsDigit) 

Func<char, bool> temp = Char.IsDigit; 
input.Where(temp); 

कि के बराबर है के बराबर है:

Func<char, bool> temp = new Func<char, bool>(Char.IsDigit); 
input.Where(temp); 

तो यह Char.IsDigit के लिए एक प्रतिनिधि बनाता है और फिर input.Where को पास कर देता।

तो दूसरा दूसरा "मैन-इन-द-बीच" (अनाम कार्य) को हटा देता है। इस विशेष मामले में यह "कानूनी" है क्योंकि अज्ञात फ़ंक्शन के i पैरामीटर को Char.IsDigit पर "जैसा है" पास किया गया है। यह अलग हो गया होता अगर यह था:

input.Where(i => !Char.IsDigit(i)) 

इस मामले में, आप नहीं निकाल सकते मैन-इन-द-मिडल (अनाम समारोह)।

इस सब के लिए कोई नाम नहीं है (या आप पहले "एक अज्ञात फ़ंक्शन में एक प्रतिनिधि को बनाने और पास करने" को कॉल कर सकते हैं और दूसरा "एक विधि समूह से बनाए गए प्रतिनिधि को बनाकर और पास कर रहा है" ... लेकिन वे सुंदर कैचफ्रेज़ नहीं हैं, वे आपके द्वारा किए जा रहे कार्यों का अधिक विवरण हैं)

+0

"इस सब के लिए कोई नाम नहीं है।" हालांकि है: यह एक * विधि समूह * है। यह भी देखें http://stackoverflow.com/questions/886822/what-is-a-method-group-in-c –

+0

@JeroenVannevel नहीं, विधि समूह 'char.IsDigit'' इनपुट में है। (Char .IsDigit) '। एक विधि समूह (जो किया जाता है) से एक प्रतिनिधि बनाना एक नाम नहीं है (या उसका नाम वास्तव में एक विधि समूह से एक प्रतिनिधि बना रहा है) – xanatos

+0

@TimSchmelter चोरी :-) – xanatos

5

आपका Where एक Func<char, bool>, जो तरीकों कि एक char तर्क लेने के लिए और एक bool लौटने के लिए एक प्रतिनिधि है की उम्मीद है। इस प्रतिनिधि से मेल खाने वाली कोई भी चीज़ इस Where के लिए एक वैध तर्क है।

  • लैम्ब्डा आप शुरू में लिखा प्रकार निष्कर्ष से इस प्रतिनिधि से मेल खाता है: संकलक को उम्मीद है कि ichar है, गणनीय स्रोत के जेनेरिक पैरामीटर के आधार पर - और bool के रूप में वापसी प्रकार infers, क्योंकि है कि क्या विधि कॉल है लैम्ब्डा के अंदर अभिव्यक्ति वापस आ जाएगी।
  • Char.IsDigit विधि स्वयं भी इससे मेल खाती है। इस प्रकार, विधि का संदर्भ देना एक ही चीज़ व्यक्त करने का एक और वैध तरीका है। इसे विधि समूह कहा जाता है।

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

Where(i => Char.IsDigit(i)) 

ऊपर gets lowered by the compiler लिए:

bool AnAnonymousMethod(char i) 
{ 
    return Char.IsDigit(i); 
} 

और उसके बाद:

Where(AnAnonymousMethod) 

आप देख सकते हैं, लैम्ब्डा वाक्यविन्यास

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

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