स्थानीय समारोह बनाम लाम्बडा सी # 7.0


178

मैं C # 7.0 में नए कार्यान्वयन को देख रहा हूं और मुझे यह दिलचस्प लगता है कि उन्होंने स्थानीय कार्यों को लागू किया है, लेकिन मैं ऐसे परिदृश्य की कल्पना नहीं कर सकता हूं जहां एक स्थानीय कार्य को लंबोदर अभिव्यक्ति पर पसंद किया जाएगा, और दोनों के बीच क्या अंतर है।

मुझे समझ में नहीं आता है कि लंबदा anonymousकार्य हैं, इस बीच स्थानीय कार्य नहीं होते हैं, लेकिन मैं एक वास्तविक विश्व परिदृश्य का पता नहीं लगा सकता, जहां स्थानीय समारोह में लंबोदर अभिव्यक्ति पर फायदे हैं

किसी भी उदाहरण की बहुत सराहना की जाएगी। धन्यवाद।


9
जेनरिक, आउट पैरामीटर, पुनरावर्ती कार्य बिना लैम्ब्डा को शून्य करने के लिए इनिशियलाइज़ करने के लिए, आदि
Kirk Woll

5
@KirkWoll - आपको इसे उत्तर के रूप में पोस्ट करना चाहिए।
Enigmativity

जवाबों:


276

यह मैड्स टॉर्गेसेन द्वारा C # डिज़ाइन मीटिंग नोट्स में समझाया गया था जहाँ स्थानीय कार्यों पर पहली बार चर्चा की गई थी :

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

इस पर कुछ और विस्तार करने के लिए, लाभ हैं:

  1. प्रदर्शन।

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

    इसके अलावा, स्थानीय फ़ंक्शन स्थानीय वेरिएबल्स को कैप्चर करने के साथ अधिक कुशल होते हैं: लैम्ब्डा आमतौर पर वेरिएबल्स को एक वर्ग में कैप्चर करते हैं, जबकि स्थानीय फ़ंक्शन एक संरचना (पास का उपयोग करके ref) का उपयोग कर सकते हैं , जो फिर से आवंटन से बचता है।

    इसका मतलब यह भी है कि स्थानीय कार्यों को कॉल करना सस्ता है और वे इनलाइन हो सकते हैं, संभवतः आगे भी प्रदर्शन बढ़ सकता है।

  2. स्थानीय कार्य पुनरावर्ती हो सकते हैं।

    लैम्ब्डा पुनरावर्ती भी हो सकता है, लेकिन इसके लिए अजीब कोड की आवश्यकता होती है, जहां आप पहले nullएक प्रतिनिधि चर और फिर लैम्ब्डा को असाइन करते हैं। स्थानीय कार्य स्वाभाविक रूप से पुनरावर्ती (पारस्परिक रूप से पुनरावर्ती सहित) हो सकते हैं।

  3. स्थानीय कार्य सामान्य हो सकते हैं।

    लैम्ब्डा सामान्य नहीं हो सकता है, क्योंकि उन्हें एक ठोस प्रकार के साथ एक चर को सौंपा जाना है (यह प्रकार बाहरी दायरे से जेनेरिक चर का उपयोग कर सकता है, लेकिन यह एक ही बात नहीं है)।

  4. स्थानीय कार्यों को एक पुनरावृत्त के रूप में लागू किया जा सकता है।

    लंबर फ़ंक्शन को लागू करने के लिए yield return(और yield break) कीवर्ड का उपयोग नहीं कर सकता है IEnumerable<T>। स्थानीय कार्य कर सकते हैं।

  5. स्थानीय कार्य बेहतर दिखते हैं।

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

    की तुलना करें:

    int add(int x, int y) => x + y;
    Func<int, int, int> add = (x, y) => x + y;

22
मैं जोड़ना चाहूंगा कि स्थानीय कार्यों में कॉलर की तरफ पैरामीटर नाम हैं। लम्बदास नहीं।
लेन्सफ्लारे

3
@ लेन्सफ्लेयर यह सच है कि लैम्ब्डा के पैरामीटर नाम संरक्षित नहीं हैं, लेकिन ऐसा इसलिए है क्योंकि उन्हें प्रतिनिधियों को परिवर्तित करना होगा, जिनके अपने नाम हैं। उदाहरण के लिए Func<int, int, int> f = (x, y) => x + y; f(arg1:1, arg2:1);:।
svick

1
महान सूची! हालाँकि, मैं कल्पना कर सकता हूँ कि कैसे IL / JIT कंपाइलर 1. में वर्णित सभी अनुकूलन कर सकता है, प्रतिनिधियों के लिए भी अगर उनका उपयोग कुछ नियमों का पालन करता है।
मार्सिन काकज़मारेक

1
@ कैसबाश क्योंकि लंबोदर हमेशा एक प्रतिनिधि का उपयोग करते हैं और वह प्रतिनिधि एक के रूप में क्लोजर रखता है object। तो, लैम्ब्डा एक संरचना का उपयोग कर सकता है, लेकिन इसे बॉक्सिंग करना होगा, इसलिए आपके पास अभी भी अतिरिक्त आवंटन होगा।
svick

1
@happybits ज्यादातर जब आपको इसे एक नाम देने की आवश्यकता नहीं होती है, जैसे कि जब आप इसे विधि से पास कर रहे हों।
svick

83

Svick के महान जवाब के अलावा स्थानीय कार्यों के लिए एक और लाभ है:
वे returnबयान के बाद भी फ़ंक्शन में कहीं भी परिभाषित किए जा सकते हैं ।

public double DoMath(double a, double b)
{
    var resultA = f(a);
    var resultB = f(b);
    return resultA + resultB;

    double f(double x) => 5 * x + 3;
}

5
यह वास्तव में उपयोगी है, क्योंकि मुझे फ़ंक्शन #region Helpersके निचले भाग में सभी सहायक कार्यों को लगाने की आदत हो सकती है , इसलिए उस फ़ंक्शन के भीतर अव्यवस्था से बचने के लिए और मुख्य रूप से मुख्य वर्ग में अव्यवस्था से बचने के लिए।
ऑस्टिनवेब्रायन

मैं भी इसकी सराहना करता हूं। यह मुख्य कार्य करता है जिसे आप पढ़ना आसान समझते हैं, क्योंकि आपको यह खोजने की आवश्यकता नहीं है कि यह कहां से शुरू होता है। यदि आप कार्यान्वयन विवरण देखना चाहते हैं, तो अंत को देखते रहें।
रेमी Despres-Smyth

3
यदि आपके कार्य इतने बड़े हैं कि उन्हें उन क्षेत्रों की आवश्यकता है, तो वे बहुत बड़े हैं।
ssmith

9

यदि आप यह भी आश्चर्यचकित करते हैं कि स्थानीय फ़ंक्शन का परीक्षण कैसे किया जाए तो आपको जस्टमॉक की जांच करनी चाहिए क्योंकि इसमें कार्य करने की कार्यक्षमता है। यहाँ एक साधारण श्रेणी का उदाहरण दिया गया है, जिसका परीक्षण किया जाएगा:

public class Foo // the class under test
{ 
    public int GetResult() 
    { 
        return 100 + GetLocal(); 
        int GetLocal () 
        { 
            return 42; 
        } 
    } 
}

और यहाँ परीक्षण कैसे दिखता है:

[TestClass] 
public class MockLocalFunctions 
{ 
    [TestMethod] 
    public void BasicUsage() 
    { 
        //Arrange 
        var foo = Mock.Create<Foo>(Behavior.CallOriginal); 
        Mock.Local.Function.Arrange<int>(foo, "GetResult", "GetLocal").DoNothing(); 

        //Act 
        var result = foo. GetResult(); 

        //Assert 
        Assert.AreEqual(100, result); 
    } 
} 

यहाँ जस्टमॉक डॉक्यूमेंट का लिंक दिया गया है

अस्वीकरण। मैं जस्टमॉक के लिए जिम्मेदार डेवलपर्स में से एक हूं


इस तरह के भावुक डेवलपर्स को देखकर बहुत अच्छा लगता है कि लोग अपने टूल का उपयोग करने की वकालत करते हैं। पूर्णकालिक नौकरी के रूप में डेवलपर टूल लिखने में आपकी रुचि कैसे हुई? एक अमेरिकी के रूप में, मेरी धारणा यह है कि ऐसे करियर खोजना मुश्किल हो सकता है जब तक कि आपके पास मास्टर्स या पीएच.डी. विज्ञान में।
जॉन ज़ब्रोस्की

हाय जॉन और इस तरह के शब्दों के लिए धन्यवाद। एक सॉफ्टवेयर डेवलपर के रूप में, मैं अपने ग्राहकों द्वारा उनके लिए प्रदान किए गए मूल्य के लिए उनकी सराहना करने से बेहतर कुछ नहीं देखता। चुनौती और प्रतिस्पर्धी काम की इच्छा के साथ गठबंधन करें और आपको उन चीजों की एक सीमित सूची प्राप्त होगी जिनके बारे में मुझे बहुत जुनून होगा। उस सूची में उत्पादकता डेवलपर टूलींग लिखना है। कम से कम मेरे दिमाग में :) करियर के बारे में, मुझे लगता है कि डेवलपर टूलिंग प्रदान करने वाली कंपनियां सभी सॉफ्टवेयर कंपनियों का काफी कम प्रतिशत हैं और यही कारण है कि ऐसा अवसर मिलना कठिन है।
Mihail Vladov

एक अलग सवाल। आप यहाँ VerifyAll को कॉल क्यों नहीं करते हैं? क्या स्थानीय कार्य को सत्यापित करने के लिए जस्टमॉक को बताने का एक तरीका है?
जॉन ज़ब्रोस्की

2
हाय @JohnZabroski, परीक्षण परिदृश्य की आवश्यकता होती है जोरदार घटनाओं की आवश्यकता नहीं है। बेशक, आप सत्यापित कर सकते हैं कि कॉल किया गया था। सबसे पहले, आपको यह निर्दिष्ट करने की आवश्यकता है कि आप विधि को कॉल किए जाने की कितनी बार अपेक्षा करते हैं। इस तरह: .DoNothing().OccursOnce();और बाद में जोर देकर कहते हैं कि कॉल Mock.Assert(foo);विधि द्वारा कॉल किया गया था । यदि आप रुचि रखते हैं कि अन्य परिदृश्यों का समर्थन कैसे किया जाता है तो आप हमारे अस्सरटिंग ऑक्यूरेंस सहायता लेख को पढ़ सकते हैं ।
व्लादोव

0

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

क्या करता है एक सर्वर के लिए एक सॉकेट कनेक्शन खुला है और एक घटना के लिए एक घटना बाध्यकारी डेटा पर पाश। कोई इसे उसी तरह से सोच सकता है जिस तरह एक वर्ग को डिज़ाइन किया गया है, केवल एक ही जगह पर सहायक तरीके नहीं लिख रहा है जो वास्तव में केवल कार्यक्षमता के एक पाइस के लिए काम कर रहे हैं। नीचे कुछ नमूने हैं कि यह कैसे दिख सकता है, कृपया ध्यान दें कि मैं चर का उपयोग कर रहा हूं और "सहायक" विधियां अंत में नीचे हैं। अंत में मैं अच्छी तरह से इवेंट हैंडलर्स को हटा देता हूं, अगर मेरा एक्सचेंज क्लास बाहरी / इंजेक्शन होगा तो मेरे पास कोई भी लंबित इवेंट हैंडलर रजिस्टर्ड नहीं होगा

void List<HistoricalData> RequestData(Ticker ticker, TimeSpan timeout)
{
    var socket= new Exchange(ticker);
    bool done=false;
    socket.OnData += _onData;
    socket.OnDone += _onDone;
    var request= NextRequestNr();
    var result = new List<HistoricalData>();
    var start= DateTime.Now;
    socket.RequestHistoricalData(requestId:request:days:1);
    try
    {
      while(!done)
      {   //stop when take to long….
        if((DateTime.Now-start)>timeout)
           break;
      }
      return result;

    }finally
    {
        socket.OnData-=_onData;
        socket.OnDone-= _onDone;
    }


   void _OnData(object sender, HistoricalData data)
   {
       _result.Add(data);
   }
   void _onDone(object sender, EndEventArgs args)
   {
      if(args.ReqId==request )
         done=true;
   } 
}

आप नीचे दिए गए लाभों को देख सकते हैं, यहां आप एक नमूना कार्यान्वयन देख सकते हैं। आशा है कि लाभ समझाने में मदद करता है।


2
1. यह एक बहुत ही जटिल उदाहरण है और केवल स्थानीय कार्यों को प्रदर्शित करने के लिए स्पष्टीकरण है। 2. इस उदाहरण में लैम्बदास के साथ तुलना करने पर स्थानीय कार्य किसी भी आवंटन से नहीं बचते हैं, क्योंकि उन्हें अभी भी प्रतिनिधियों में बदलना है। इसलिए मैं नहीं देखता कि वे जीसी से कैसे बचेंगे।
svick

1
चर / नकल चर के आसपास नहीं, svick का जवाब बाकी वास्तव में अच्छी तरह से शामिल किया गया है। उसके उत्तर की नकल करने की आवश्यकता नहीं है
वाल्टर वेव्सोवेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.