कीवर्ड बनाम लैम्ब्डा नोटेशन देखें


जवाबों:


140

संक्षिप्त उत्तर: नहीं।

लंबा जवाब जो प्रासंगिक नहीं हो सकता है:

  • यदि आप एक प्रतिनिधि प्रकार (जैसे Funcया) के लिए लैम्ब्डा असाइन करते हैंAction ) के तो आपको एक अनाम प्रतिनिधि मिलेगा।
  • यदि आप लैम्ब्डा को एक अभिव्यक्ति प्रकार के लिए असाइन करते हैं, तो आपको एक अनाम प्रतिनिधि के बजाय एक अभिव्यक्ति ट्री मिलेगा। अभिव्यक्ति के पेड़ को फिर एक गुमनाम प्रतिनिधि के लिए संकलित किया जा सकता है।

संपादित करें: यहां एक्सप्रेशन के लिए कुछ लिंक दिए गए हैं।

  • System.Linq.Expression.Expression (TDelegate) (यहां शुरू करें)।
  • प्रतिनिधियों के साथ लाइनक इन-मेमोरी (जैसे System.Func) System.Linq.Enumerable का उपयोग करता है । Linq to SQL (और कुछ भी) अभिव्यक्तियों के साथ System.Linq.Queryable का उपयोग करता है । उन तरीकों पर मापदंडों की जाँच करें।
  • स्कॉटगू से एक स्पष्टीकरण । संक्षेप में, Linq-in-memory आपकी क्वेरी को हल करने के लिए कुछ अनाम विधियाँ उत्पन्न करेगा। SQL को Linq एक अभिव्यक्ति ट्री का उत्पादन करेगा जो क्वेरी का प्रतिनिधित्व करता है और फिर उस ट्री को T-SQL में अनुवाद करता है। Linq to Entities एक अभिव्यक्ति पेड़ का निर्माण करेगी जो क्वेरी का प्रतिनिधित्व करता है और फिर उस पेड़ को उचित SQL में मंच में अनुवाद करता है।

3
एक अभिव्यक्ति प्रकार? यह मेरे लिए नए क्षेत्र की तरह लगता है। मैं अभिव्यक्ति के प्रकार और C # में अभिव्यक्ति पेड़ों का उपयोग करने के बारे में अधिक जानकारी कहां प्राप्त कर सकता हूं?
मोजोफिल्टर

2
यहां तक ​​कि लंबे समय तक जवाब - वहाँ अलग-अलग प्रतिनिधि प्रकारों के लिए परिवर्तनीय कारण हैं, भी :)
जॉन स्कीट

ध्यान दें कि लैम्ब्डा केवल एक्सप्रेशन प्रकार को सौंपा जा सकता है, अगर यह एक एक्सप्रेशन लैम्ब्डा है।
मीका विडेनमैन

125

मुझे एमी का जवाब पसंद है, लेकिन मुझे लगा कि मुझे पांडित्य होगा। प्रश्न कहता है, "एक बार यह संकलित किया जाता है" - जो बताता है कि दोनों अभिव्यक्तियों को संकलित किया गया है। वे दोनों कैसे संकलित कर सकते हैं, लेकिन एक प्रतिनिधि के रूप में और एक को अभिव्यक्ति पेड़ में परिवर्तित किया जा सकता है? यह एक मुश्किल है - आपको गुमनाम तरीकों की एक और विशेषता का उपयोग करना होगा; केवल वही जो लंबोदर भावों द्वारा साझा नहीं किया गया है। यदि आप किसी पैरामीटर सूची को निर्दिष्ट किए बिना एक अनाम विधि निर्दिष्ट करते हैं , तो यह किसी भी प्रतिनिधि प्रकार के रिटर्निंग शून्य और बिना किसी outपैरामीटर के संगत है । इस ज्ञान के साथ सशस्त्र, हमें अभिव्यक्तियों को पूरी तरह से अस्पष्ट लेकिन बहुत अलग बनाने के लिए दो अधिभार का निर्माण करने में सक्षम होना चाहिए।

लेकिन आपदा आघात! कम से कम C # 3.0 के साथ, आप एक लैम्ब्डा एक्सप्रेशन को ब्लॉक बॉडी के साथ एक एक्सप्रेशन में नहीं बदल सकते - और न ही आप लैम्बडा एक्सप्रेशन को बॉडी में असाइनमेंट के साथ बदल सकते हैं (भले ही इसे रिटर्न वैल्यू के रूप में इस्तेमाल किया जाए)। यह C # 4.0 और .NET 4.0 के साथ बदल सकता है, जो अभिव्यक्ति ट्री में अधिक व्यक्त होने की अनुमति देता है। तो दूसरे शब्दों में, MojoFilter देने के लिए उदाहरणों के साथ, दोनों को लगभग हमेशा एक ही चीज़ में बदल दिया जाएगा। (एक मिनट में अधिक जानकारी।)

हम प्रतिनिधि मापदंडों चाल का उपयोग कर सकते हैं यदि हम निकायों को थोड़ा बदल देते हैं:

using System;
using System.Linq.Expressions;

public class Test
{
    static void Main()
    {
        int x = 0;
        Foo( () => x );
        Foo( delegate { return x; } );
    }

    static void Foo(Func<int, int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }

    static void Foo(Expression<Func<int>> func)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

लेकिन रुकें! हम अभिव्यक्ति के पेड़ों का उपयोग किए बिना भी दोनों के बीच अंतर कर सकते हैं, अगर हम पर्याप्त रूप से चालाक हों। नीचे दिए गए उदाहरण में अधिभार संकल्प नियमों (और अनाम प्रतिनिधि मिलान चाल) का उपयोग किया गया है ...

using System;
using System.Linq.Expressions;

public class Base
{
    public void Foo(Action action)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

public class Derived : Base
{
    public void Foo(Action<int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        int x = 0;
        d.Foo( () => { x = 0; } );
        d.Foo( delegate { x = 0; } );
    }
}

आउच। बच्चों को याद रखें, हर बार जब आप बेस क्लास से विरासत में मिली विधि को ओवरलोड करते हैं, तो थोड़ा बिल्ली का बच्चा रोने लगता है।


9
मैंने अपना पॉपकॉर्न निकाला और पूरी बात पढ़ी। यह कुछ ऐसा भेद है जिसके बारे में मैं कभी सोच भी नहीं पाऊंगा, भले ही मैं इसे सही तरीके से देख रहा हो।
मोजोफिल्टर

27
मुझे इसके बारे में कुछ पता था, लेकिन मुझे इसे मनुष्यों तक पहुंचाने की आपकी क्षमता पर बधाई देना चाहिए।
एमी बी

1
.NET 4.0 (CTP पर आधारित) में परिवर्तन के इच्छुक किसी भी व्यक्ति के लिए - marcgravell.blogspot.com/2008/11/future-expressions.html देखें । ध्यान दें कि C # 4.0 अभी तक कुछ भी नया नहीं करता है जहाँ तक मैं बता सकता हूँ।
मार्क Gravell

4
जॉन, तुम रॉक। एरिक, एक सच्चे स्कीट फैनबी होने के लिए, आपको उसके स्टैक ओवरफ्लो आरएस की तरह सदस्यता लेनी चाहिए जैसे मैं हूं। बस अपने फ़ीड रीडर में stackoverflow.com/users/22656 छड़ी ।
पॉल बैटम

3
@RoyiNamir: यदि आप एक पैरामीटर सूची के बिना एक अनाम विधि का उपयोग करते हैं, तो यह गैर-रेफ / आउट मापदंडों के साथ किसी भी प्रतिनिधि प्रकार के साथ संगत है , इसलिए जब तक वापसी प्रकार संगत नहीं होता है। मूल रूप से आप कह रहे हैं "मुझे मापदंडों की परवाह नहीं है"। ध्यान दें कि delegate { ... }यह समान नहीं है delegate() { ... }- उत्तरार्द्ध केवल एक पैरामीटर रहित प्रतिनिधि प्रकार के साथ संगत है।
जॉन स्कीट

2

ऊपर के दो उदाहरणों में कोई अंतर नहीं है, शून्य।

भाव:

() => { x = 0 }

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

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 

6
निश्चित रूप से इसका मतलब है कि "एक का संकलन होगा, दूसरा नहीं होगा";)
जॉन स्कीट

2

एमी बी सही है। ध्यान दें कि अभिव्यक्ति पेड़ों का उपयोग करने के लिए फायदे हो सकते हैं। LINQ to SQL एक्सप्रेशन ट्री की जाँच करेगा और इसे SQL में बदलेगा।

प्रभावी ढंग से रिफैक्टिंग-सुरक्षित तरीके से कक्षा सदस्यों के नाम को एक फ्रेमवर्क में पास करने के लिए आप लामाओं और अभिव्यक्ति पेड़ों के साथ चालें भी खेल सकते हैं। Moq इसका एक उदाहरण है।


-1

इसमे अंतर है

उदाहरण:

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(delegate
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});   

और मैं लैम्ब्डा से प्रतिस्थापित करता हूं: (त्रुटि)

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});

गलत ~ लैम्ब्डा केवल इसलिए विफल हो गया क्योंकि विधि पैरामीटर हस्ताक्षर मेल नहीं खाता है।
जैक वांग

-1

यहाँ कुछ मूल बातें।

यह एक अनाम विधि है

(string testString) => { Console.WriteLine(testString); };

चूंकि अनाम विधियों में नाम नहीं होते हैं इसलिए हमें एक प्रतिनिधि की आवश्यकता होती है जिसमें हम इन विधियों या अभिव्यक्तियों को निर्दिष्ट कर सकते हैं। जैसे

delegate void PrintTestString(string testString); // declare a delegate

PrintTestString print = (string testString) => { Console.WriteLine(testString); }; 
print();

लंबोदर अभिव्यक्ति के साथ भी। आमतौर पर हमें उनका उपयोग करने के लिए एक प्रतिनिधि की आवश्यकता होती है

s => s.Age > someValue && s.Age < someValue    // will return true/false

हम इस अभिव्यक्ति का उपयोग करने के लिए एक फंक प्रतिनिधि का उपयोग कर सकते हैं।

Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;

bool result = checkStudentAge ( Student Object);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.