मेमने के भाव में रेफरी या आउट पैरामीटर का उपयोग नहीं कर सकते


173

आप लंबोदर अभिव्यक्ति में रेफरी या आउट पैरामीटर का उपयोग क्यों नहीं कर सकते हैं?

मैं आज त्रुटि के पार आया और एक समाधान पाया, लेकिन मैं अभी भी उत्सुक था कि यह संकलन-समय की त्रुटि क्यों है।

CS1628 : अनाम विधि, लैम्ब्डा एक्सप्रेशन या क्वेरी एक्सप्रेशन के अंदर पैरामीटर 'पैरामीटर' को रेफ या आउट में उपयोग नहीं किया जा सकता है

यहाँ एक सरल उदाहरण दिया गया है:

private void Foo()
{
    int value;
    Bar(out value);
}

private void Bar(out int value)
{
    value = 3;
    int[] array = { 1, 2, 3, 4, 5 };
    int newValue = array.Where(a => a == value).First();
}

यह पुनरावृत्तियों के बारे में है, लेकिन इस पोस्ट में एक ही तर्क के बहुत (एरिक लिपर्ट और mdash द्वारा भी; वह सब के बाद भाषा डिजाइन टीम पर है) lambdas पर लागू होता है: < blogs.msdn.com/ericlippert-archive/2009/07/13 /… >
जोएल कोएहॉर्न

17
क्या मैं पूछ सकता हूं कि आपको क्या मिला था?
बीटल्स 1692

3
आप बस एक स्थानीय सामान्य चर घोषित कर सकते हैं और उसी के साथ काम कर सकते हैं, और परिणाम को बाद में मान सकते हैं ... एक var temVValb = मान जोड़ें; और फिर tempValue के साथ काम करें।
नशे में कोड बंदर

जवाबों:


122

लैम्ब्डा के पास चर के जीवनकाल को बदलने की उपस्थिति है जिसे वे कैप्चर करते हैं। उदाहरण के लिए निम्नलिखित लैम्ब्डा अभिव्यक्ति पैरामीटर p1 को मौजूदा विधि फ्रेम की तुलना में अधिक समय तक जीने का कारण बनता है क्योंकि विधि फ्रेम के ढेर पर नहीं रहने के बाद इसके मूल्य को एक्सेस किया जा सकता है।

Func<int> Example(int p1) {
  return () => p1;
}

कैप्चर किए गए वेरिएबल्स की एक और संपत्ति यह है कि लैम्बडा एक्सप्रेशन के बाहर वेरिएबल में बदलाव भी दिखाई देते हैं। उदाहरण के लिए निम्नलिखित प्रिंट 42

void Example2(int p1) {
  Action del = () => { p1 = 42; }
  del();
  Console.WriteLine(p1);
}

ये दो गुण प्रभाव का एक निश्चित सेट उत्पन्न करते हैं जो निम्न तरीकों से रेफ पैरामीटर के चेहरे पर उड़ते हैं

  • रेफ पैरामीटर एक निश्चित जीवनकाल हो सकता है। एक समारोह में रेफरी पैरामीटर के रूप में एक स्थानीय चर पास करने पर विचार करें।
  • लैम्ब्डा में साइड इफेक्ट्स को रिफ पैरामीटर पर ही दिखाई देना चाहिए। दोनों विधि के भीतर और कॉलर में।

ये कुछ असंगत गुण हैं और एक कारण यह है कि वे लंबोदर अभिव्यक्तियों में अस्वीकृत हैं।


36
मैं समझता हूं कि हम refलंबोदर अभिव्यक्ति का उपयोग नहीं कर सकते हैं , लेकिन इसका उपयोग करने की इच्छा को खिलाया नहीं गया है।
जियोनी

85

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

delegate void TestDelegate (out int x);
static void Main(string[] args)
{
    TestDelegate testDel = (out int x) => { x = 10; };
    int p;
    testDel(out p);
    Console.WriteLine(p);
}

70

आप कर सकते हैं लेकिन आपको सभी प्रकारों को स्पष्ट रूप से परिभाषित करना चाहिए

(a, b, c, ref d) => {...}

हालाँकि, अमान्य है

(int a, int b, int c, ref int d) => {...}

यह सही है


13
ऐसा होता है; सवाल यह है कि आप क्यों नहीं कर सकते; जवाब है आप कर सकते हैं
बेन एडम्स

24
यह नहीं है; सवाल यह है कि आप एक मौजूदा चर का संदर्भ नहीं दे सकते हैं , जो पहले से ही परिभाषित है refया out, लंबोदर के अंदर। यदि आप उदाहरण कोड पढ़ते हैं तो यह स्पष्ट है (इसे फिर से पढ़ने के लिए पुनः प्रयास करें)। स्वीकृत उत्तर स्पष्ट रूप से समझाता है कि क्यों। आपका उत्तर लैम्ब्डा के उपयोग refया out पैरामीटर के बारे में है । पूरी तरह से सवाल का जवाब नहीं देने और कुछ और बोलने के बारे में
edc65

4
@ edc65 सही है ... इसका सवाल के विषय से कोई लेना-देना नहीं है, जो कि लांबा अभिव्यक्ति की सामग्री के बारे में है (दाईं ओर), इसकी पैरामीटर सूची नहीं (बाईं ओर)। यह विचित्र है कि इससे 26 अपवित्र हुए।
जिम बाल्टर

6
हालांकि इससे मुझे मदद मिली। उसके लिए +1। धन्यवाद
Emad

1
लेकिन मुझे अभी भी समझ में नहीं आया कि इसे इस तरह से क्यों बनाया गया है। मुझे सभी प्रकारों को स्पष्ट रूप से परिभाषित क्यों करना है? शब्दार्थ मुझे इसकी आवश्यकता नहीं है। क्या मैं कुछ खो रहा हूँ?
जो

5

चूँकि यह Google पर "C # lambda ref" के लिए शीर्ष परिणामों में से एक है; मुझे लगता है कि मुझे उपरोक्त उत्तरों पर विस्तार करने की आवश्यकता है। पुराने (C # 2.0) अनाम प्रतिनिधि सिंटैक्स काम करता है और यह अधिक जटिल हस्ताक्षर (साथ ही बंद) का समर्थन करता है। लैम्ब्डा और अनाम प्रतिनिधियों ने बहुत कम से कम संकलक बैकएंड में कथित कार्यान्वयन साझा किया है (यदि वे समान नहीं हैं) - और सबसे महत्वपूर्ण बात, वे क्लोजर का समर्थन करते हैं।

जब मैंने खोज की, तो सिंटैक्स प्रदर्शित करने के लिए मैं क्या करने की कोशिश कर रहा था:

public static ScanOperation<TToken> CreateScanOperation(
    PrattTokenDefinition<TNode, TToken, TParser, TSelf> tokenDefinition)
{
    var oldScanOperation = tokenDefinition.ScanOperation; // Closures still work.
    return delegate(string text, ref int position, ref PositionInformation currentPosition)
        {
            var token = oldScanOperation(text, ref position, ref currentPosition);
            if (token == null)
                return null;
            if (tokenDefinition.LeftDenotation != null)
                token._led = tokenDefinition.LeftDenotation(token);
            if (tokenDefinition.NullDenotation != null)
                token._nud = tokenDefinition.NullDenotation(token);
            token.Identifier = tokenDefinition.Identifier;
            token.LeftBindingPower = tokenDefinition.LeftBindingPower;
            token.OnInitialize();
            return token;
        };
}

बस ध्यान रखें कि लैम्ब्डा प्रक्रियात्मक और गणितीय रूप से सुरक्षित हैं (क्योंकि पहले उल्लेख किए गए रेफरी मूल्य संवर्धन के कारण): आप कीड़े के डिब्बे खोल सकते हैं। इस सिंटैक्स का उपयोग करते समय ध्यान से सोचें।


3
मुझे लगता है कि आपने प्रश्न को गलत समझा। सवाल यह था कि एक लैंबडा अपने कंटेनर विधि में रेफरी / आउट वेरिएबल्स तक क्यों नहीं पहुंच सकता है, न कि लैम्ब्डा में ही रेफरी / आउट वैरिएबल क्यों नहीं हो सकते। AFAIK बाद के लिए कोई अच्छा कारण नहीं है। आज मैंने एक लंबोदर लिखा (a, b, c, ref d) => {...}और refत्रुटि संदेश "पैरामीटर" 4 के साथ लाल-रेखांकित किया गया था जिसे 'रेफरी' कीवर्ड के साथ घोषित किया जाना चाहिए। Facepalm! पुनश्च "रेफरी वैल्यू प्रमोशन" क्या है?
क्वर्टी

1
@Qwertie मुझे पूर्ण परिमाणीकरण के साथ काम करने के लिए मिला है, अर्थ, a, b, c और d पर प्रकारों को शामिल करता है और यह काम करता है। बेन एडम्स का उत्तर देखें (हालांकि वह मूल प्रश्न को गलत समझ रहा है, भी)।
एड बेयेट्स 19

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

इसका वास्तव में पूछे गए प्रश्न से कोई लेना-देना नहीं है ... बेन एडम्स के उत्तर के तहत स्वीकृत उत्तर और टिप्पणियों को देखें, जो इस प्रश्न को गलत समझते हैं।
जिम बाल्टर

1

और शायद यह?

private void Foo()
{
    int value;
    Bar(out value);
}

private void Bar(out int value)
{
    value = 3;
    int[] array = { 1, 2, 3, 4, 5 };
    var val = value; 
    int newValue = array.Where(a => a == val).First();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.