c# - सी#में लैम्ब्डा द्वारा बनाए गए प्रतिनिधि का जीवनकाल क्या है?





delegates lambda (5)


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

मैंने आपको कम से कम उखाड़ फेंक दिया है, इसलिए उम्मीद है कि कोई आपको वह अकादमिक उत्तर दे सकता है जिसे आप ढूंढ रहे हैं।

Lambdas अच्छा हैं, क्योंकि वे brevity और इलाके और encapsulation का एक अतिरिक्त रूप प्रदान करते हैं । एक बार जब आप लैम्ब्डा का उपयोग कर सकते हैं तो केवल उन कार्यों को लिखने के बजाय उपयोग किया जाता है।

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

यह कार्यान्वयन काम करता है, हालांकि शायद अधिक मात्रा में (अभी भी इसका शोध कर रहा है), मेरी धारणा को सही साबित करना साबित करता है।

एक छोटा सा उदाहरण:

class SomeClass
{
    public void Bleh()
    {
        Action action = () => {};
    }

    public void CallBleh()
    {
        Bleh();  // `action` == {Method = {Void <SomeClass>b__0()}}
        Bleh();  // `action` still == {Method = {Void <SomeClass>b__0()}}
    }
}

क्या लैम्ब्डा कभी एक नया उदाहरण लौटाएगा, या क्या यह हमेशा एक जैसा होने की गारंटी है?




मुझे लगता है कि जब मैं जवाब दे रहा था, तब स्कीट कूद गया, इसलिए मैं उस बिंदु को कम नहीं करूँगा। एक चीज जो मैं सुझाऊंगा, बेहतर तरीके से समझने के लिए कि आप चीजों का उपयोग कैसे कर रहे हैं, रिवर्स इंजीनियरिंग टूल्स और आईएल से परिचित होना है। सवाल में कोड नमूना लें और आईएल को रिवर्स इंजीनियर लें। कोड आपको काम करने के तरीके के बारे में बड़ी जानकारी देगा।




यह किसी भी तरह से गारंटी नहीं है।

वर्तमान एमएस कार्यान्वयन के बारे में मुझे क्या याद है:

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

संपादित करें: सी # 4 spec का प्रासंगिक पाठ खंड 6.5.1 में है:

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




यहां आपके प्रश्न और जॉन के जवाब पर आपकी टिप्पणी के आधार पर मुझे लगता है कि आप कई चीजों को भ्रमित कर रहे हैं। यह सुनिश्चित करने के लिए कि यह स्पष्ट है:

  • एक दी गई लैम्ब्डा के लिए प्रतिनिधि का समर्थन करने वाली विधि हमेशा वही होती है।
  • विधि जो "समान" लैम्ब्डा के लिए प्रतिनिधि को वापस ले जाती है जो कि दो बार प्रकट होती है, वही होने की अनुमति है, लेकिन अभ्यास में हमारे कार्यान्वयन में समान नहीं है।
  • दिए गए लैम्ब्डा के लिए बनाया गया प्रतिनिधि उदाहरण हमेशा कैसा हो सकता है, इस पर निर्भर करता है कि संकलक कैशिंग के बारे में कितना स्मार्ट है।

तो अगर आपके पास कुछ ऐसा है:

for(i = 0; i < 10; ++i)
    M( ()=>{} )

फिर हर बार एम को बुलाया जाता है, आपको प्रतिनिधि का एक ही उदाहरण मिलता है क्योंकि संकलक स्मार्ट है और उत्पन्न करता है

static void MyAction() {}
static Action DelegateCache = null;

...
for(i = 0; i < 10; ++i)
{
    if (C.DelegateCache == null) C.DelegateCache = new Action ( C.MyAction )
    M(C.DelegateCache);
}

यदि आपके पास है

for(i = 0; i < 10; ++i)
    M( ()=>{this.Bar();} )

तो संकलक उत्पन्न करता है

void MyAction() { this.Bar(); }
...
for(i = 0; i < 10; ++i)
{
    M(new Action(this.MyAction));
}

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

कंपाइलर को अनुमति है (लेकिन वास्तव में इस समय नहीं) उत्पन्न होता है

void MyAction() { this.Bar(); }
Action DelegateCache = null;
...
for(i = 0; i < 10; ++i)
{
    if (this.DelegateCache == null) this.DelegateCache = new Action ( this.MyAction )
    M(this.DelegateCache);
}

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

यदि आपके पास है

Action a1 = ()=>{};
Action a2 = ()=>{};

फिर अभ्यास में संकलक इसे उत्पन्न करता है

static void MyAction1() {}
static void MyAction2() {}
static Action ActionCache1 = null;
static Action ActionCache2 = null;
...
if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
Action a1 = ActionCache1;
if (ActionCache2 == null) ActionCache2 = new Action(MyAction2);
Action a2 = ActionCache2;

हालांकि संकलक को यह पता लगाने की अनुमति है कि दो भेड़ के बच्चे समान हैं और उत्पन्न होते हैं

static void MyAction1() {}
static Action ActionCache1 = null;
...
if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
Action a1 = ActionCache1;
Action a2 = ActionCache1;

क्या अब यह स्पष्ट है?




दो प्रश्न चिह्न (??) इंगित करते हैं कि यह एक कोलेसिंग ऑपरेटर है।

Coalescing ऑपरेटर एक श्रृंखला से पहले गैर-नल मूल्य लौटाता है। आप इस यूट्यूब वीडियो को देख सकते हैं जो पूरी चीज को व्यावहारिक रूप से प्रदर्शित करता है।

लेकिन मुझे वीडियो कहने के लिए और अधिक जोड़ने दें।

यदि आप कोलेसिंग के अंग्रेजी अर्थ को देखते हैं तो यह "एक साथ समेकित" कहता है। उदाहरण के लिए नीचे एक सरल कोलेसिंग कोड है जो चार तारों को चेन करता है।

तो यदि str1 null है तो यह str2 का प्रयास str2 , अगर str2 null यह str2 का प्रयास str3 और तब तक जब तक यह एक गैर-शून्य मान के साथ स्ट्रिंग पाता है।

string final = str1 ?? str2 ?? str3 ?? str4;

सरल शब्दों में कोलेसिंग ऑपरेटर एक श्रृंखला से पहला गैर-नल मूल्य देता है।





c# delegates lambda