क्या "उपज तोड़ता है?" सी # में करते हैं?


493

मैंने इस वाक्यविन्यास को MSDN में देखा है: yield breakलेकिन मुझे नहीं पता कि यह क्या करता है। क्या कोई जानता है?


26
फिर भी, MSDN दस्तावेज़ीकरण इसका उल्लेख करता है, लेकिन इसकी व्याख्या नहीं करता है। यह एक भूखे डेवलपर को चिढ़ाने का एक बुरा तरीका है।
फिल

3
यील्ड रिटर्न एक बैकिंग लिस्ट की जरूरत को खत्म कर देता है, MyList.Add(...)बस आपको कुछ करने की जरूरत नहीं है yield return ...। यदि आपको समय से पहले लूप से बाहर निकलने और आपके द्वारा उपयोग की जाने वाली वर्चुअल बैकिंग सूची को वापस करने की आवश्यकता हैyield break;
द मफिन मैन

जवाबों:


529

यह निर्दिष्ट करता है कि एक पुनरावृत्ति समाप्त हो गई है। आप yield breakएक returnबयान के रूप में सोच सकते हैं जो एक मूल्य वापस नहीं करता है।

उदाहरण के लिए, यदि आप एक फ़ंक्शन को पुनरावृत्त के रूप में परिभाषित करते हैं, तो फ़ंक्शन का शरीर इस तरह दिखाई दे सकता है:

for (int i = 0; i < 5; i++)
{
    yield return i;
}

Console.Out.WriteLine("You will see me");

ध्यान दें कि लूप अपने सभी चक्रों को पूरा करने के बाद, अंतिम पंक्ति निष्पादित हो जाती है और आपको अपने कंसोल ऐप में संदेश दिखाई देगा।

या इस तरह के साथ yield break:

int i = 0;
while (true)
{
    if (i < 5)
    {
        yield return i;
    }
    else
    {
        // note that i++ will not be executed after this
        yield break;
    }
    i++;
}

Console.Out.WriteLine("Won't see me");

इस मामले में अंतिम विवरण को कभी भी निष्पादित नहीं किया जाता है क्योंकि हमने फ़ंक्शन को जल्दी छोड़ दिया है।


8
क्या यह आपके उदाहरण के breakबजाय बस yield breakऊपर हो सकता है? कंपाइलर उस पर शिकायत नहीं करता है।
orad

85
@orad breakइस मामले में एक सरल लूप बंद हो जाएगा, लेकिन यह विधि निष्पादन को समाप्त नहीं करेगा, इस प्रकार अंतिम पंक्ति निष्पादित होगी और "मुझे पाठ नहीं दिखाई देगा" वास्तव में देखा जाएगा।
दामिर ज़ेकिउ

5
@Damir Zekić क्या आप अपने जवाब में यह भी जोड़ सकते हैं कि आपको रिटर्न पर यील्ड ब्रेक पसंद क्यों करना चाहिए और दोनों में क्या अंतर हैं?
ब्रूनो कोस्टा

11
@ DamirZekić की वापसी और उपज का टूटना समान नहीं है। यदि आप अशक्त लौटते हैं, तो आपके पास NullReferenceExceptionIEnumerable का एन्यूमरेटर हो सकता है , जबकि उपज विराम के साथ आप नहीं (कोई तत्व के साथ कोई उदाहरण नहीं है)।
ब्रूनो कोस्टा

6
@BrunoCosta एक ही विधि में नियमित रिटर्न देने की कोशिश कर रहा है एक संकलक त्रुटि देता है। yield return xसंकलक का उपयोग करके आप चाहते हैं कि यह विधि एक Enumeratorवस्तु बनाने के लिए वाक्यविन्यास चीनी हो । इस एन्यूमरेटर में विधि MoveNext()और संपत्ति है Current। MoveNext () एक yield returnस्टेटमेंट तक विधि को निष्पादित करता है , और उस मान को चालू करता है Current। अगली बार MoveNext कहा जाता है, निष्पादन वहाँ से जारी है। yield breakइस एन्यूमरेटर के अंत को इंगित करने के लिए करंट को शून्य पर सेट करें, ताकि यह foreach (var x in myEnum())समाप्त हो जाए।
वोल्फजून

57

एक इटरेटर ब्लॉक को समाप्त करता है (जैसे कहता है कि IEnumerable में अधिक तत्व नहीं हैं)।


2
[+1] के साथ - हालांकि अकादमिक रूप से .NET में कोई पुनरावृत्तियों नहीं हैं। केवल एनुमरेटर्स (एक दिशा, आगे।)
शॉन विल्सन

@Shaun विल्सन, लेकिन साथ yieldकीवर्ड आप दोनों दिशाओं में संग्रह पुनरावृति कर सकते हैं, इसके अलावा आप संग्रह के हर अगले तत्व में नहीं एक पंक्ति ले जा सकते हैं
मॉन्स्टर

@ आप किसी भी फैशन में संग्रह को प्रसारित कर सकते हैं और आपको yieldइसे करने की आवश्यकता नहीं है। मैं यह नहीं कह रहा हूं कि आप गलत हैं, मैं देख रहा हूं कि आप क्या सुझाव दे रहे हैं; लेकिन, अकादमिक रूप से .NET में कोई पुनरावृत्तियों नहीं हैं, केवल enumerators (एक दिशा, आगे) - stdc ++ के विपरीत कोई सीटीएस / सीएलआर में परिभाषित "जेनेरिक इटरेटर फ्रेमवर्क" नहीं है। LINQ विस्तार विधियों के साथ अंतर को बंद करने में मदद करता है जो yield return कॉलबैक विधियों का उपयोग करते हैं और करते हैं, लेकिन वे प्रथम श्रेणी के एक्सटेंशन तरीके हैं, न कि प्रथम श्रेणी के विधायक। परिणामी IEnumerableस्वयं को आगे wrt कॉलर के अलावा किसी भी दिशा में पुनरावृति नहीं कर सकता है।
शॉन विल्सन

29

इट्टर को बताता है कि यह अंत तक पहुँच गया है।

उदहारण के लिए:

public interface INode
{
    IEnumerable<Node> GetChildren();
}

public class NodeWithTenChildren : INode
{
    private Node[] m_children = new Node[10];

    public IEnumerable<Node> GetChildren()
    {
        for( int n = 0; n < 10; ++n )
        {
            yield return m_children[ n ];
        }
    }
}

public class NodeWithNoChildren : INode
{
    public IEnumerable<Node> GetChildren()
    {
        yield break;
    }
}

21

yieldमूल रूप से एक IEnumerable<T>विधि को सहकारिता के समान व्यवहार करता है (पूर्व निर्धारित के विपरीत) अनुसूचित धागा।

yield returnCPU के नियंत्रण को छोड़ने के लिए "शेड्यूल" या "स्लीप" फ़ंक्शन को थ्रेड करने जैसा है। एक धागे की तरह, IEnumerable<T>विधि तुरंत बाद बिंदु पर नियंत्रण रखती है, सभी स्थानीय चर के समान मूल्य होते हैं जैसा कि नियंत्रण से पहले दिया गया था।

yield break अपने कार्य के अंत तक पहुँचने और समाप्त करने वाले धागे की तरह है।

लोग "राज्य मशीन" के बारे में बात करते हैं, लेकिन एक राज्य मशीन वास्तव में एक "धागा" है। एक थ्रेड में कुछ अवस्थाएँ (स्थानीय चर का मान) होती हैं, और हर बार यह निर्धारित होता है कि नए राज्य तक पहुँचने के लिए इसमें कुछ कार्रवाई हो। इसके बारे yieldमें मुख्य बिंदु यह है कि हम जिस ऑपरेटिंग सिस्टम थ्रेड का उपयोग कर रहे हैं, उसके विपरीत, कोड का उपयोग करने वाला यह समय में जमे हुए है जब तक कि यह मैन्युअल रूप से उन्नत या समाप्त नहीं हो जाता है।


13

जॉनर स्कीट की पुस्तक C # इन डेप्थ से इस नि: शुल्क नमूने के अध्याय में पुनरावृत्त ब्लॉकों का पूरा विषय अच्छी तरह से कवर किया गया है


आपने अभी मुझे एक प्रति बेची है। धन्यवाद! :-)
जॉन श्नाइडर

9

इस yield breakबयान के कारण गणना रूक जाती है। वास्तव में, yield breakकिसी भी अतिरिक्त आइटम को वापस किए बिना गणना को पूरा करता है।

विचार करें कि वास्तव में दो तरीके हैं जो एक पुनरावृत्ति विधि को रोकना रोक सकते हैं। एक मामले में, सभी वस्तुओं को वापस करने के बाद विधि का तर्क स्वाभाविक रूप से विधि से बाहर निकल सकता है। यहाँ एक उदाहरण है:

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount)
{
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;
    }

    Debug.WriteLine("All the primes were found.");
}

उपरोक्त उदाहरण में, पुनरावृत्तियाँ मिलने के बाद इट्रेटर विधि स्वाभाविक रूप से निष्पादित करना बंद कर देगी maxCount

यह yield breakकथन एन्यूमरेट करने के लिए पुनरावृत्ति करने वाले के लिए एक और तरीका है। यह एन्यूमरेशन से जल्दी बाहर निकलने का एक तरीका है। यहाँ ऊपर जैसा ही तरीका है। इस बार, विधि में समय की मात्रा पर एक सीमा है जिसे विधि निष्पादित कर सकती है।

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount, int maxMinutes)
{
    var sw = System.Diagnostics.Stopwatch.StartNew();
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;

        if (sw.Elapsed.TotalMinutes > maxMinutes)
            yield break;
    }

    Debug.WriteLine("All the primes were found.");
}

को फोन पर सूचना दें yield break। वास्तव में, यह गणना को जल्दी से बाहर निकाल रहा है।

यह भी ध्यान दें कि yield breakकाम एक सादे से अलग है break। उपरोक्त उदाहरण में, yield breakकॉल किए बिना विधि से बाहर निकलता है Debug.WriteLine(..)


7

यहाँ http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/ बहुत अच्छा उदाहरण है:

सार्वजनिक स्थिर IEnumerable <int> रेंज (int न्यूनतम, int अधिकतम)
{
   जबकि (सच)
   {
      अगर (न्यूनतम> = अधिकतम)
      {
         उपज टूटना;
      }
      उपज वापसी मिनट ++;
   }
}

और स्पष्टीकरण, कि यदि किसी yield breakकथन को किसी विधि के भीतर मारा जाता है, तो उस पद्धति का निष्पादन बिना किसी रिटर्न के रुक जाता है। कुछ समय परिस्थितियां हैं, जब आप कोई परिणाम नहीं देना चाहते हैं, तो आप उपज विराम का उपयोग कर सकते हैं।


5

यील्ड ब्रेक अंतिम समय के लिए रिटर्न कहने का एक तरीका है और किसी भी मूल्य को वापस नहीं करता है

जैसे

// returns 1,2,3,4,5
IEnumerable<int> CountToFive()
{
    yield return 1;
    yield return 2;
    yield return 3;
    yield return 4;
    yield return 5;
    yield break;
    yield return 6;
    yield return 7;
    yield return 8;
    yield return 9;
 }

4

यदि आपका मतलब "क्या उपज तोड़ता है वास्तव में है", "यह कैसे काम करता है" - विवरण के लिए देखें रेमंड चेन का ब्लॉग https://devblogs.microsoft.com/oldnewthing/20080812-00/?p=21273

C # पुनरावृत्तियाँ कुछ बहुत ही जटिल कोड उत्पन्न करती हैं।


12
ठीक है, वे केवल जटिल हैं यदि आप उस कोड के बारे में परवाह करते हैं जो वे संकलित हैं। कोड जो उनका उपयोग करता है वह बहुत सरल है।
रॉबर्ट रोसनी

@ रॉबर्ट, यही मेरा मतलब है इसलिए मैंने आपकी टिप्पणी को शामिल करने के लिए जवाब अपडेट किया है
टोनी ली

-2

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

एक उदाहरण का उपयोग कर अर्थ समझाने के लिए:

    public IEnumerable<int> SampleNumbers()
    {
        int counter = 0;
        yield return counter;

        counter = counter + 2;

        yield return counter;

        counter = counter + 3;

        yield return counter ;
    }

मान जब लौटाए जाते हैं, तो ये हैं: 0, 2, 5।

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


11
आप की व्याख्या नहीं की थी क्या yield breakकरता है
जे सुलिवन

मुझे नहीं लगता कि yield returnवास्तव में कई मूल्यों को वापस करने का समर्थन करता है। हो सकता है कि आप वास्तव में क्या मतलब नहीं है, लेकिन है कि मैं इसे कैसे पढ़ा है।
सैम

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

इसका कारण यह है yield breakकि यह एक खराब उदाहरण है कि इसमें लैंग्वेज-लेवल एन्यूमरेटर नहीं है जैसे foreach- जब एन्यूमरेटर का उपयोग yield breakवास्तविक मूल्य प्रदान करता है। यह उदाहरण एक अनियंत्रित लूप की तरह दिखता है। आप वास्तविक दुनिया में लगभग कभी भी इस कोड को नहीं देख सकते हैं (हम कुछ किनारे के मामलों के बारे में सोच सकते हैं), निश्चित रूप से, यहां कोई "पुनरावृत्ति करने वाला" नहीं है। "इटरेटर ब्लॉक" भाषा विनिर्देश के विषय के रूप में विधि से आगे नहीं बढ़ सकता है। वास्तव में जो लौटाया जा रहा है वह एक "enumerable" है, यह भी देखें: stackoverflow.com/questions/742497/…
शॉन विल्सन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.