'उपज वापसी' का उचित उपयोग


903

उपज कीवर्ड उन में से एक है खोजशब्दों है कि मुझे रहस्यमय करना करने के लिए जारी सी # में, और मुझे विश्वास है कि मैं इसे सही ढंग से उपयोग कर रहा हूँ कभी नहीं किया गया है।

निम्नलिखित दो टुकड़ों में से, कौन सा पसंदीदा है और क्यों?

संस्करण 1: उपज वापसी का उपयोग करना

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        foreach (Product product in products)
        {
            yield return product;
        }
    }
}

संस्करण 2: सूची लौटाएं

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        return products.ToList<Product>();
    }
}

38
yieldसे बंधा है IEnumerable<T>और अपनी तरह का है। यह किसी आलसी मूल्यांकन में है
२२:२२ पर जैदर

इसी तरह के सवाल का एक शानदार जवाब है। stackoverflow.com/questions/15381708/…
संजीव राय

1
यहाँ एक अच्छा उपयोग उदाहरण है: stackoverflow.com/questions/3392612/…
ValGe

6
मुझे यह देखने के लिए एक अच्छा मामला है yield returnकि क्या कोड जो परिणामों के माध्यम से पुनरावृत्ति करता है GetAllProducts(), उपयोगकर्ता को समय से पहले प्रसंस्करण को रद्द करने का मौका देता है।
जेएमडी

2
मुझे यह धागा वास्तव में मददगार लगा: प्रोग्रामर.स्टैकएक्सचेंज.
com

जवाबों:


806

जब मैं सूची (या वस्तुओं के अगले समूह) में अगले आइटम की गणना करता हूं तो मैं उपज-वापसी का उपयोग करता हूं।

अपने संस्करण 2 का उपयोग करते हुए, आपके पास लौटने से पहले पूरी सूची होनी चाहिए। उपज-वापसी का उपयोग करके, आपको वास्तव में केवल लौटने से पहले अगले आइटम की आवश्यकता होती है।

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

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

आपके विशेष उदाहरण में, आपके पास उत्पादों की पूरी सूची है, इसलिए मैं संस्करण 2 का उपयोग करूंगा।


31
मैं चाहता हूँ कि प्रश्न 3 में आपके उदाहरण में दो लाभ हैं। 1) यह कम्प्यूटेशनल लागत (कभी-कभी एक लाभ, कभी-कभी नहीं) 2 फैलता है) यह कई उपयोग के मामलों में अनिश्चित काल तक गणना से बच सकता है। आप संभावित कमी का उल्लेख करने में विफल रहते हैं जो इसे मध्यवर्ती स्थिति के आसपास रखता है। यदि आपके पास मध्यवर्ती राज्य की महत्वपूर्ण मात्रा है (डुप्लिकेट उन्मूलन के लिए एक हाशसेट कहते हैं) तो उपज का उपयोग आपके मेमोरी फ़ुटप्रिंट को बढ़ा सकता है।
केनेट बेलेंकी

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

2
और अंत में ... एक बहुत ही क्रमबद्ध रूप में एसिंक्रोनस कोड लिखने के लिए उपज का उपयोग करने के लिए थोड़ा विस्की लेकिन कभी-कभी प्रभावी तकनीक है।
केनेट बेलेंकी

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

1
Yield returnअपने स्वयं के कस्टम इट्रेटर क्लास (आईईएनयुमेटर लागू करें) लिखने के लिए शॉर्टहैंड लगता है। इसलिए, उल्लिखित लाभ कस्टम पुनरावृत्ति वर्गों पर भी लागू होते हैं। वैसे भी, दोनों निर्माण मध्यवर्ती राज्य रखते हैं। अपने सबसे सरल रूप में यह वर्तमान वस्तु का संदर्भ रखने के बारे में है।
जे। औवेहंड

641

एक अस्थायी सूची बनाना पूरी वीडियो को डाउनलोड करने जैसा है, जबकि उपयोग yieldकरना उस वीडियो को स्ट्रीम करने जैसा है।


180
मुझे पूरी तरह से पता है कि यह उत्तर तकनीकी उत्तर नहीं है, लेकिन मेरा मानना ​​है कि उपज और वीडियो स्ट्रीमिंग के बीच समानता उपज कीवर्ड को समझने के दौरान एक अच्छा उदाहरण है। इस विषय के बारे में सब कुछ तकनीकी पहले से ही कहा गया है, इसलिए मैंने "दूसरे शब्दों में" समझाने की कोशिश की। क्या कोई सामुदायिक नियम है जो कहता है कि आप अपने विचारों को गैर-तकनीकी शब्दों में नहीं समझा सकते हैं?
अनार खलीलोव

13
मुझे यकीन नहीं है कि किसने आपको वोट दिया या क्यों (मैं चाहता हूं कि उन्होंने टिप्पणी की होगी), लेकिन मुझे लगता है कि यह कुछ हद तक गैर-तकनीकी संभावना से इसका वर्णन करता है।
सीनो जूल

22
अभी भी अवधारणा को लोभी और इससे ध्यान केंद्रित करने में मदद मिली, अच्छा सादृश्य।
टोनी

11
मुझे यह उत्तर पसंद है, लेकिन यह प्रश्न का उत्तर नहीं देता है।
14

73

समझने के लिए एक वैचारिक उदाहरण के रूप में, जब आप उपयोग करना चाहते हैं yield, मान लें कि जिस विधि ConsumeLoop()द्वारा आइटम लौटाया गया है / उसके द्वारा उपज ProduceList():

void ConsumeLoop() {
    foreach (Consumable item in ProduceList())        // might have to wait here
        item.Consume();
}

IEnumerable<Consumable> ProduceList() {
    while (KeepProducing())
        yield return ProduceExpensiveConsumable();    // expensive
}

इसके बिना yield, कॉल ProduceList()में लंबा समय लग सकता है क्योंकि आपको लौटने से पहले सूची पूरी करनी होगी:

//pseudo-assembly
Produce consumable[0]                   // expensive operation, e.g. disk I/O
Produce consumable[1]                   // waiting...
Produce consumable[2]                   // waiting...
Produce consumable[3]                   // completed the consumable list
Consume consumable[0]                   // start consuming
Consume consumable[1]
Consume consumable[2]
Consume consumable[3]

का उपयोग करते हुए yield, यह पुनर्व्यवस्थित हो जाता है, "समानांतर में" काम करने का प्रकार:

//pseudo-assembly
Produce consumable[0]
Consume consumable[0]                   // immediately Consume
Produce consumable[1]
Consume consumable[1]                   // consume next
Produce consumable[2]
Consume consumable[2]                   // consume next
Produce consumable[3]
Consume consumable[3]                   // consume next

और अंत में, जैसा कि पहले ही कई सुझाव दे चुके हैं, आपको संस्करण 2 का उपयोग करना चाहिए क्योंकि आपके पास पहले से ही पूरी सूची वैसे भी है।


30

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

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

उपज कीवर्ड का उपयोग करते हुए (रोब ईसेनबर्ग के कैलिबर्न.माइक्रो कोरटाइन्स कार्यान्वयन के साथ) मुझे इस तरह एक वेब सेवा के लिए एक अतुल्यकालिक कॉल व्यक्त करने की अनुमति देता है:

public IEnumerable<IResult> HandleButtonClick() {
    yield return Show.Busy();

    var loginCall = new LoginResult(wsClient, Username, Password);
    yield return loginCall;
    this.IsLoggedIn = loginCall.Success;

    yield return Show.NotBusy();
}

यह क्या करेगा मेरे बिजीइंडिएटर को चालू करें, मेरी वेब सेवा पर लॉग इन विधि को कॉल करें, मेरे इस्लेगेड को ध्वज को वापसी मान पर सेट करें, और फिर बिजीइंडिलेटर को वापस बंद करें।

यहां बताया गया है कि यह कैसे काम करता है: IResult में एक निष्पादित विधि और एक पूर्ण घटना है। Caliburn.Micro IEleumerator को CallleButtonClick () के कॉल से पकड़ लेता है और इसे Coroutine.BeginExecute विधि में पास कर देता है। BeginExecute विधि IResults के माध्यम से चलना शुरू करता है। जब पहला IResult वापस आ जाता है, तो HandleButtonClick () के अंदर निष्पादन रोक दिया जाता है, और BeginExecute () एक ईवेंट हैंडलर को कंप्लीट इवेंट में अटैच करता है और एक्सक्यूट () कहता है। IResult.Execute () या तो एक सिंक्रोनस या एक एसिंक्रोनस कार्य कर सकता है और पूरा होने वाली घटना को पूरा करता है।

LoginResult कुछ इस तरह दिखता है:

public LoginResult : IResult {
    // Constructor to set private members...

    public void Execute(ActionExecutionContext context) {
        wsClient.LoginCompleted += (sender, e) => {
            this.Success = e.Result;
            Completed(this, new ResultCompletionEventArgs());
        };
        wsClient.Login(username, password);
    }

    public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
    public bool Success { get; private set; }
}

यह इस तरह से कुछ स्थापित करने और निष्पादन के माध्यम से यह देखने में मदद कर सकता है कि क्या चल रहा है।

आशा है कि यह किसी को मदद करता है! मैंने वास्तव में विभिन्न तरीकों से खोज करने का आनंद लिया है, जिनका उपयोग किया जा सकता है।


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

yieldइस तरह से उपयोग करना मेरे लिए कभी नहीं हुआ । ऐसा लगता है कि एसिंक्स / प्रतीक्षारत पैटर्न का अनुकरण करने के लिए एक सुंदर तरीका है (जो मुझे लगता है कि इसके बजाय इसका इस्तेमाल किया जाएगा yieldअगर इसे आज फिर से लिखा जाए)। क्या आपने पाया है कि इन yieldसवालों के रचनात्मक उपयोग ने पिछले कुछ वर्षों में पैदावार कम नहीं की है, क्योंकि सी # इस सवाल का जवाब देने के बाद से विकसित हुआ है? या आप अभी भी इस तरह के आधुनिक चतुर उपयोग-मामलों के साथ आ रहे हैं? और यदि हां, तो क्या आप हमारे लिए एक और दिलचस्प परिदृश्य साझा करना चाहेंगे?
यह उतार चढ़ाव भरा

27

यह एक विचित्र सुझाव की तरह लग रहा है, लेकिन मैंने yieldपायथन में जनरेटर पर एक प्रस्तुति को पढ़कर C # में कीवर्ड का उपयोग करना सीखा : डेविड एम। बेज़ले की http://www.dabeaz.com/generators/Generators.pdf । प्रस्तुति को समझने के लिए आपको बहुत अधिक पायथन जानने की आवश्यकता नहीं है - मैंने नहीं किया। मुझे यह समझाने में बहुत मदद मिली कि न केवल जनरेटर कैसे काम करते हैं बल्कि आपको क्यों परवाह करनी चाहिए।


1
प्रस्तुति एक साधारण अवलोकन प्रदान करती है। यह कैसे सी # में काम करता है में दिए गए लिंक में रे चेन से चर्चा कर रहे हैं के विवरण stackoverflow.com/a/39507/939250 पहले लिंक विस्तार से बताते हैं उपज वापसी के तरीकों के अंत में एक दूसरे, अंतर्निहित वापसी नहीं है।
डोनाल्ड लाफर्टी

18

यील्ड रिटर्न एल्गोरिदम के लिए बहुत शक्तिशाली हो सकता है जहां आपको लाखों वस्तुओं के माध्यम से पुनरावृति करने की आवश्यकता होती है। निम्नलिखित उदाहरण पर विचार करें जहां आपको सवारी साझा करने के लिए संभावित यात्राओं की गणना करने की आवश्यकता है। पहले हम संभावित यात्राएं उत्पन्न करते हैं:

    static IEnumerable<Trip> CreatePossibleTrips()
    {
        for (int i = 0; i < 1000000; i++)
        {
            yield return new Trip
            {
                Id = i.ToString(),
                Driver = new Driver { Id = i.ToString() }
            };
        }
    }

फिर प्रत्येक यात्रा के माध्यम से पुनरावृति:

    static void Main(string[] args)
    {
        foreach (var trip in CreatePossibleTrips())
        {
            // possible trip is actually calculated only at this point, because of yield
            if (IsTripGood(trip))
            {
                // match good trip
            }
        }
    }

यदि आप उपज के बजाय सूची का उपयोग करते हैं, तो आपको मेमोरी (~ 190mb) में 1 मिलियन ऑब्जेक्ट आवंटित करने की आवश्यकता होगी और यह सरल उदाहरण ~ 1400ms को चलाने में ले जाएगा। हालाँकि, यदि आप उपज का उपयोग करते हैं, तो आपको इन सभी अस्थायी वस्तुओं को मेमोरी में डालने की आवश्यकता नहीं है और आपको काफी तेज एल्गोरिथ्म गति प्राप्त होगी: यह उदाहरण बिना किसी मेमोरी खपत के चलाने के लिए केवल ~ 400ms का समय लगेगा।


2
उपज के अंतर्गत क्या उपज है? मुझे लगा होगा कि यह एक सूची थी, इसलिए यह स्मृति के उपयोग को कैसे बेहतर बनाएगी?
रोल

1
@ रोल yieldआंतरिक रूप से एक राज्य मशीन को लागू करके कवर के तहत काम करता है। यहां 3 विस्तृत MSDN ब्लॉग पोस्ट के साथ SO उत्तर दिया गया है जो कार्यान्वयन को बहुत विस्तार से समझाते हैं। रेमंड चेन @ MSFT द्वारा लिखित
शिव

13

कोड के दो टुकड़े वास्तव में दो अलग-अलग काम कर रहे हैं। पहला संस्करण सदस्यों को खींचेगा क्योंकि आपको उनकी आवश्यकता है। दूसरा संस्करण मेमोरी में सभी परिणामों को लोड करेगा इससे पहले कि आप इसके साथ कुछ भी करना शुरू कर दें।

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

हालांकि ध्यान रखने वाली महत्वपूर्ण बात यह है कि: अंतर दक्षता में हैं। इस प्रकार, आपको संभवत: जो भी आपके कोड को सरल बनाता है और प्रोफाइलिंग के बाद ही इसे बदल देना चाहिए।


11

यील्ड के दो बेहतरीन उपयोग हैं

यह अस्थायी संग्रह बनाने के साथ कस्टम पुनरावृत्ति प्रदान करने में मदद करता है। (सभी डेटा और लूपिंग लोड करना)

यह स्टेटफुल इट्रीशन करने में मदद करता है। (स्ट्रीमिंग)

नीचे एक सरल वीडियो है जिसे मैंने उपरोक्त दो बिंदुओं का समर्थन करने के लिए पूर्ण प्रदर्शन के साथ बनाया है

http://www.youtube.com/watch?v=4fju3xcm21M


10

यह वही है जो क्रिस सेल उन बयानों के बारे में सी # प्रोग्रामिंग भाषा में बताता है ;

मैं कभी-कभी यह भूल जाता हूं कि यील्ड रिटर्न रिटर्न के समान नहीं है, जिसमें यील्ड रिटर्न के बाद कोड निष्पादित किया जा सकता है। उदाहरण के लिए, पहले रिटर्न के बाद कोड को कभी भी निष्पादित नहीं किया जा सकता है:

    int F() {
return 1;
return 2; // Can never be executed
}

इसके विपरीत, यहाँ पहली पैदावार वापसी के बाद कोड निष्पादित किया जा सकता है:

IEnumerable<int> F() {
yield return 1;
yield return 2; // Can be executed
}

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

IEnumerable<int> F() {
if(...) { yield return 1; } // I mean this to be the only
// thing returned
yield return 2; // Oops!
}

इन मामलों में, यह याद रखना कि पैदावार वापसी "अंतिम" नहीं है, जैसे रिटर्न मददगार है।


अस्पष्टता में कटौती करने के लिए कृपया स्पष्ट करें कि आप कब कर सकते हैं, क्या यह है, या हो सकता है? क्या यह संभव है कि पहली बार वापस लौटा जाए और दूसरी उपज का निष्पादन न किया जाए?
जॉनो क्रॉफर्ड

@ जोहानक्रॉफोर्ड दूसरी उपज का विवरण केवल तभी निष्पादित करेगा जब IEnumerable का दूसरा / अगला मूल्य गणना किया जाता है। यह पूरी तरह से संभव है कि यह अभ्यस्त हो, जैसे F().Any()- यह केवल पहले परिणाम की गणना करने की कोशिश करने के बाद वापस आ जाएगा। सामान्य तौर पर, आपको IEnumerable yieldप्रोग्राम बदलने की स्थिति पर भरोसा नहीं करना चाहिए , क्योंकि यह वास्तव में ट्रिगर नहीं हो सकता है
Zac Faragher

8

अपने उत्पादों को मानते हुए LINQ वर्ग, एन्यूमरेटिंग / पुनरावृत्ति के लिए एक समान उपज का उपयोग करता है, पहला संस्करण अधिक कुशल है क्योंकि इसके पुनरावृत्त होने पर हर बार इसका एक ही मूल्य प्राप्त होता है।

दूसरा उदाहरण Enumerator / Iterator को ToList () विधि के साथ एक सूची में परिवर्तित कर रहा है। इसका मतलब यह है कि यह मैन्युअल रूप से एन्यूमरेटर की सभी वस्तुओं पर निर्भर करता है और फिर एक फ्लैट सूची देता है।


8

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

public static IEnumerable<Product> AllProducts
{
    get {
        using (AdventureWorksEntities db = new AdventureWorksEntities()) {
            var products = from product in db.Product
                           select product;

            return products;
        }
    }
}

ज़रूर, यह थोड़ा अधिक बॉयलर-प्लेट है, लेकिन इसका उपयोग करने वाला कोड बहुत अधिक क्लीनर लगेगा:

prices = Whatever.AllProducts.Select (product => product.price);

बनाम

prices = Whatever.GetAllProducts().Select (product => product.price);

नोट: मैं ऐसा किसी भी तरीके के लिए नहीं करूंगा जो उनके काम करने में थोड़ा समय ले सकता है।


7

और इस बारे में क्या?

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        return products.ToList();
    }
}

मुझे लगता है कि यह बहुत साफ है। हालाँकि, जाँच के लिए मेरे पास VS2008 नहीं है। किसी भी मामले में, यदि उत्पाद IEnumerable को लागू करता है (जैसा कि ऐसा लगता है - यह एक फ़ार्च स्टेटमेंट में उपयोग किया जाता है), मैं इसे सीधे वापस करूँगा।


2
उत्तर पोस्ट करने के बजाय अधिक जानकारी शामिल करने के लिए कृपया ओपी संपादित करें।
ब्रायन रासमुसेन

ठीक है, आपको मुझे बताना होगा कि ओपी वास्तव में क्या करता है :-) धन्यवाद
पेट्र के।

मूल पोस्ट, मुझे लगता है। मैं पोस्ट संपादित नहीं कर सकता, इसलिए यह जाने का रास्ता प्रतीत हो रहा था।
पेट्र के।

5

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

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

कुछ उदाहरण जहां उपज का उपयोग किया जा सकता है, वह है:

  1. जटिल, चरण-दर-चरण गणना जहां कॉलर एक समय में एक कदम के डेटा की प्रतीक्षा कर रहा है
  2. GUI में पेजिंग - जहां उपयोगकर्ता कभी भी अंतिम पृष्ठ तक नहीं पहुंच सकता है और वर्तमान पृष्ठ पर केवल उप-जानकारी का खुलासा करने की आवश्यकता होती है

आपके प्रश्नों का उत्तर देने के लिए, मैंने संस्करण 2 का उपयोग किया होगा।


3

सीधे सूची वापस करें। लाभ:

  • यह अधिक स्पष्ट है
  • सूची पुन: प्रयोज्य है। (पुनरावृत्त नहीं है) वास्तव में सच नहीं है, धन्यवाद जॉन

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


यह न भूलें कि यह IEnumerable <T> में लौट रहा है, न कि IEnumerator <T> - आप GetEnumerator को फिर से कॉल कर सकते हैं।
जॉन स्केट

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

1

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

मान लीजिए कि यदि डेवलपर कुछ संग्रह को फ़िल्टर कर रहा है, तो संग्रह को पुन: प्रदर्शित कर रहा है और फिर उन वस्तुओं को कुछ नए संग्रह में निकाल रहा है। इस तरह की पाइपलाइन काफी नीरस है।

के बारे में अधिक कीवर्ड यहाँ इस लेख में


-4

उपज का उपयोग कीवर्ड रिटर्न के समान है , सिवाय इसके कि यह एक जनरेटर लौटाएगा । और जनरेटर ऑब्जेक्ट केवल एक बार पार हो जाएगा ।

उपज के दो फायदे हैं:

  1. आपको इन मूल्यों को दो बार पढ़ने की आवश्यकता नहीं है;
  2. आप कई बच्चे नोड प्राप्त कर सकते हैं, लेकिन उन सभी को स्मृति में नहीं रखना है।

एक और स्पष्ट व्याख्या है शायद आपकी मदद करें।

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