2010-07-19 14 views
11

मैं इसे कुछ समय के लिए समझने की कोशिश कर रहा हूं (ऑनलाइन ब्लॉग और आर्टिकलाइज़ पढ़ रहा हूं), लेकिन अब तक असफल रहा है।लैम्ब्डा अभिव्यक्तियों और प्रतिनिधियों को समझना

प्रतिनिधियों क्या हैं? लैम्ब्डा अभिव्यक्ति क्या हैं? दोनों के फायदे और नुकसान? एक या दूसरे का उपयोग कब करना संभव सबसे अच्छा अभ्यास?

अग्रिम धन्यवाद।

+4

[सी #: प्रतिनिधि कीवर्ड बनाम लैम्ब्डा नोटेशन] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/299703/c-delegate-keyword-vs-lambda-notation) – Randolpho

+1

रैंडोल्फो, यह इसका डुप्लिकेट नहीं है सवाल। मैं एक लैम्ब्डा अभिव्यक्ति और एक प्रतिनिधि के मूल स्तर पर समझ की तलाश में हूं। – user279521

+5

@Randolpho: जरूरी नहीं कि यहां एक डुप्लिकेट हो। मुझे लगता है कि ओपी के सवाल का सबसे बड़ा हिस्सा यह पूछने में है कि वे क्या हैं, जबकि आप जिस प्रश्न का जिक्र कर रहे हैं वह केवल दोनों के बीच भेद से संबंधित है। –

उत्तर

23

प्रतिनिधि तरीकों कि आप चर के रूप में उपयोग कर सकते हैं, उदाहरण के लिए तार आदि की तरह आप एक तर्क के साथ एक प्रतिनिधि प्रणाली की घोषणा कर सकते हैं।आप एक तर्क इस तरह के साथ किसी भी कक्षा में एक विधि है:

void SomeMethod(string someArgument) {}

यह प्रतिनिधि के हस्ताक्षर से मेल खाता है, और इस तरह अपनी तरह का एक चर को सौंपा जा सकता:

OneArgumentDelegate ThisIsAVariable = new OneArgumentDelegate(SomeMethod); 
OneArgumentDelegate ThisIsAlsoAVariable = SomeMethod; // Shorthand works too

ये तो तरीकों के तर्क के रूप में पारित किया जा सकता है लागू है, तो जैसे:

void Main() 
{ 
    DoStuff(PrintString); 
} 

void PrintString(string text) 
{ 
    Console.WriteLine(text); 
} 

void DoStuff(OneArgumentDelegate action) 
{ 
    action("Hello!"); 
}

हो जाएगा ताकि उत्पादन Hello!

लैम्ब्डा अभिव्यक्ति DoStuff(PrintString) के लिए एक शॉर्टेंड हैं इसलिए आपको प्रत्येक प्रतिनिधि चर के लिए एक विधि बनाने की आवश्यकता नहीं है जिसका आप उपयोग करने जा रहे हैं। आप एक अस्थायी विधि बनाते हैं जो विधि पर पास हो जाती है। यह इस तरह से काम करता है:

DoStuff(string text => Console.WriteLine(text)); // single line 
DoStuff(string text => // multi line 
{ 
    Console.WriteLine(text); 
    Console.WriteLine(text); 
});

लैम्ब्डा भाव सिर्फ एक आशुलिपि हैं, तो आप के रूप में अच्छी एक अलग विधि बना सकते हैं और उस पर पारित हो सकता है। मुझे आशा है कि आप इसे बेहतर समझेंगे ;-)

+1

लैम्बडा अभिव्यक्ति में इनपुट चर के प्रकार की घोषणा करने के लिए ज्यादातर मामलों में अनावश्यक है, और आईएमओ, कोड को आवश्यक रूप से वर्बोज़ बनाता है (कुछ लैम्ब्डा अभिव्यक्ति पहले स्थान पर हल करने का प्रयास कर रही थी। DoStuff (txt => Console.WriteLine (txt)) समान रूप से पर्याप्त है। – Chris

+0

+1 एक सभ्य स्पष्टीकरण - मैंने ऑनलाइन देखा है उससे अधिक निश्चित रूप से बेहतर। – CJM

+2

@ क्रिस मैंने इसे छोड़ने के बारे में सोचा लेकिन स्पष्टता के लिए इसके खिलाफ फैसला किया। इसे यहां छोड़कर लोगों को भ्रमित कर सकता है जो वाक्यविन्यास से परिचित नहीं हैं। 'वास्तविक' कोड में, जैसा कि आप सुझाव देते हैं, मैं आमतौर पर इसे छोड़ देता हूं। –

6

प्रतिनिधि एक ऐसी वस्तु है जो किसी फ़ंक्शन का संदर्भ रखती है। कई अलग-अलग प्रतिनिधि एक ही कार्य को इंगित कर सकते हैं। प्रतिनिधि का प्रकार किसी फ़ंक्शन के पदचिह्न को परिभाषित करता है जो यह इंगित कर सकता है।

लैम्ब्डा अभिव्यक्ति एक ऐसा फ़ंक्शन है जिसका नाम नहीं है। इस फ़ंक्शन को निष्पादित करने का एकमात्र तरीका है फ़ंक्शन को इंगित करने वाले प्रतिनिधि। लैम्ब्डा अभिव्यक्ति आमतौर पर उस जगह पर परिभाषित किया जाता है जहां आपको किसी दिए गए पदचिह्न के साथ किसी फ़ंक्शन में प्रतिनिधि की आवश्यकता होती है। यह कोड कम वर्बोज़ बनाने के लिए उपयोगी है और साथ ही अधिक वर्णनात्मक और लचीला

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

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

दूसरी ओर, आपको अक्सर कुछ छोटी प्रक्रियाओं की आवश्यकता होती है जिन्हें आप कॉलबैक तरीके से निष्पादित करना चाहते हैं। यह वह बिंदु है जहां आप प्यार लैम्ब्डा अभिव्यक्तियों को प्यार कर सकते हैं।

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

लैबडा LINQ के साथ संयोजन के रूप में शानदार हैं।

निष्कर्ष करने के लिए, मैं yet another उद्धृत करने के लिए MSDN खंड चाहिए पढ़ने के लिए है:

आप विधि आधारित सिंटेक्स का उपयोग करते हैं कॉल करने के लिए कहाँ Enumerable कक्षा में विधि (आप के लिए वस्तुओं और LINQ करने के लिए LINQ में क्या रूप में एक्सएमएल) पैरामीटर एक प्रतिनिधि प्रकार सिस्टम है। फनक। एक लैम्ब्डा अभिव्यक्ति उस प्रतिनिधि को बनाने का सबसे सुविधाजनक तरीका है। जब आप एक ही विधि को कॉल करते हैं, उदाहरण के लिए, System.Linq.Queryable क्लास (जैसा कि आप LINQ से SQL में करते हैं) तो पैरामीटर प्रकार एक सिस्टम है .Linq.Expressions.Expression जहां Func सोलह तक कोई Func प्रतिनिधि है इनपुट पैरामीटर। फिर, एक लैम्ब्डा अभिव्यक्ति उस अभिव्यक्ति के पेड़ को बनाने के लिए एक बहुत ही संक्षिप्त तरीका है। लैम्ब्डा कहां कॉल को समान दिखने की इजाजत देता है हालांकि वास्तव में लैम्ब्डा से बनाई गई वस्तु का प्रकार अलग होता है। ज्यादा एक इंटरफेस की तरह

delegate void OneArgumentDelegate(string argument);

यह कुछ भी नहीं है,:

+0

जानकारी के लिए धन्यवाद। क्या आप उदाहरण दे सकते हैं कि आप एक प्रतिनिधि का उपयोग कब करेंगे और जब आप लैम्ब्डा अभिव्यक्ति का उपयोग करेंगे? – user279521

2

प्रतिनिधि सिर्फ काम करने के लिए सूचक है। इसका सिर्फ एक "चर" है, जहां आप एक और समारोह है कि

public class test { 
    Action<int> CallUserCode; 

    public test(Action<int> proc){ 
     CallUserCode = proc; 
    } 

    void foo(){ 
     int someValue = 0; 
     //do some stuff that needs to call the user procedure 
     CallUserCode(someValue); 
    } 
} 

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

void bar(){ 
    var t = new test(x => { /* do something with the value i get from foo */}); 
    t.foo(); //here function foo gets called, which will call 'do something' AND call my lambda expression 
} 
1

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

string mystring = SomeObject.GetMyString(); 
AnotherObject.OnSomeEvent += (eventparams => 
{ 
    string newstring = string.Format(eventparams.Message, mystring); 
    SomeService.PrintEvent(newstring); 
} 

इस तरह, mystring प्रतिनिधि में शामिल किया जाता है और एक चर के रूप में इस्तेमाल किया जा सकता।

+1

आप अज्ञात प्रतिनिधि बना सकते हैं, जो बंद हैं। अभिव्यक्ति पेड़ का उल्लेख करने के लिए –

3

किसी ने भी अज्ञात प्रतिनिधियों का उल्लेख नहीं किया है। तुम्हें पता है, मक्खी पर प्रतिनिधियों बना सकते हैं उन्हें घोषित करने के बिना:

public void Action(Func<int, int> func); 
... 
Action(delegate(int x) { return x*x; }); 

सिर्फ लैम्ब्डा वाक्य रचना का एक और अधिक वर्बोज़ संस्करण है कौन सा:

Action(x => x*x); 

यह भी ध्यान रखें लैम्ब्डा वाक्यविन्यास और अधिक आक्रामक प्रकार निष्कर्ष है। एक और अंतर यह है कि लैम्ब्डा संकेतन अभिव्यक्ति पेड़ घोषित करने के लिए इस्तेमाल किया जा सकता है:

public void Action(Expression<Func<int, int>>); 
Action(x => x*x); 

जो मामले तुम क्या मिल में एक समारोह लेकिन एक पार्स पेड़ है कि आप क्रम में जांच कर सकते हैं नहीं है। उदाहरण के लिए, linq क्वेरी उनके एसक्यूएल का निर्माण कैसे करती है।

संपादित

अधिक सीधे जब एक या अन्य का उपयोग करने के सवाल का जवाब देने के लिए:

आप शायद ही कभी, एक नया प्रतिनिधि खुद टाइप घोषित करने के लिए की जरूरत है, हालांकि यह कभी कभी उपयोगी है। फ्रेमवर्क प्रकारों के साथ Action<T> और Predicate<T> के साथ प्रदान करता है जो आम तौर पर आपको चाहिए।

फ़्लाई पर 'फ़ंक्शन' बनाते समय, लैम्ब्डा सिंटैक्स के बजाय अज्ञात प्रतिनिधि वाक्यविन्यास का उपयोग करने का कोई फायदा नहीं होता है। चूंकि लैम्ब्डा सिंटैक्स अधिक संक्षिप्त और टाइप-अनुमानित है, इसे पसंद करें।

+0

+1। जबकि आपको उन्हें * LINQ से SQL का उपयोग करने की आवश्यकता नहीं है, वे भाषा की एक महत्वपूर्ण विशेषता है। इसके अलावा, सी # 3.0 में लैम्बडास जोड़े जाने से पहले, लैम्ब्डा जैसे अर्थशास्त्र प्राप्त करने का एकमात्र तरीका अज्ञात प्रतिनिधियों का उपयोग करना था। मुझे याद है कि सी # 2.0 कोड में बहुत कुछ है। –

+0

व्यक्तिगत रूप से मैं lambdas +1 को एनन प्रतिनिधि वाक्यविन्यास पसंद करता हूं – UpTheCreek

2

वहां एक महत्वपूर्ण अंतर है जहां हम प्रतिनिधि से लैम्डा का उपयोग कर सकते हैं।

private delegate int emptymethoddel(); 
// Delegate for method with no params and returns int 

बराबर ढांचे प्रतिनिधि प्रकार है: Func<int>

लेकिन आप नए प्रतिनिधि उदाहरण/पैरामिट्रीकृत विधि से समारोह नहीं बना सकते।

private int TwoArgMethod(int i, int j) 
{ 
    return i + j; 
} 

लेकिन lambda साथ, आप उपरोक्त विधि के लिए प्रतिनिधि मिल सकती है।

Func<int> retmethod =() => TwoArgMethod(10, 20); 

लेकिन प्रतिनिधि इन्स्टेन्शियशन के लिए, जैसा कि नीचे

emptymethoddel retmethod4 = new emptymethoddel(TwoArgMethod(10,20)); 
// mismatch method signature 

ऐसा नहीं कर सकते लैम्ब्डा के साथ, हम तरीकों की ओर इशारा है कि "समारोह" या किसी अन्य वेरिएंट से मेल नहीं खाता मिल सकता है।

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