2010-04-16 16 views
5

मैं एक तरीका है जिसमें मैं yield return का उपयोग यह काम नहीं करता साथ एक छोटी सी समस्या हो रही है का उपयोग करते समय कहा जाता है नहीं ...विधि उपज वापसी

public IEnumerable<MyClass> SomeMethod(int aParam) 
{ 
    foreach(DataRow row in GetClassesFromDB(aParam).Rows) 
    { 
     yield return new MyClass((int)row["Id"], (string)row["SomeString"]); 
    }  
} 

ऊपर कोड कभी नहीं चलाता है, कॉल है जब इस विधि से बनाया गया यह सिर्फ इसके ऊपर कदम है।

लेकिन अगर मैं करने के लिए बदल ...

public IEnumerable<MyClass> SomeMethod(int aParam) 
{ 
    IList<MyClass> classes = new List<MyClass>(); 

    foreach(DataRow row in GetClassesFromDB(aParam).Rows) 
    { 
     classes.Add(new MyClass((int)rows["Id"], (string)row["SomeString"]); 
    } 

    return classes; 
} 

यह सिर्फ ठीक काम करता है।

मुझे समझ में नहीं आता कि पहली विधि कभी क्यों नहीं चलती है, क्या आप यह समझने में मेरी सहायता कर सकते हैं कि यहां क्या हो रहा है?

+0

आप विधि को कैसे कॉल करते हैं? – gammelgul

+0

इस तरह के एक निर्माता में कॉल करना: 'Prop = SomeMethod (param);' – DaveParsons

उत्तर

7

"उपज" संस्करण केवल "रन" होता है जब कॉलर वास्तव में लौटा संग्रह की गणना करना शुरू करता है।

, तो उदाहरण के लिए, आप केवल संग्रह मिलती है:

var results = SomeObject.SomeMethod (5); 

और इसके साथ कुछ भी नहीं करते, SomeMethod पर अमल नहीं होंगे।

केवल तभी जब आप results संग्रह की गणना करना शुरू करते हैं, तो यह हिट हो जाएगा।

foreach (MyClass c in results) 
{ 
    /* Now it strikes */ 
} 
+0

शानदार, बिल्कुल मुझे क्या पता होना चाहिए! धन्यवाद – DaveParsons

2

yield return तरीकों वास्तव में राज्य मशीन वर्गों है कि सूचना lazily पुनः प्राप्त में बदला जाता है - केवल जब आप वास्तव में यह मांग करते हैं। इसका मतलब है कि वास्तव में डेटा खींचने के लिए, आपको अपनी विधि के परिणामस्वरूप फिर से शुरू करना होगा।

// Gives you an iterator object that hasn't done anything yet 
IEnumerable<MyClass> list = SomeMethod(); 

// Enumerate over the object 
foreach (var item in list) { 
    // Only here will the data be retrieved. 
    // The method will stop on yield return every time the foreach loops. 
} 

दूसरे मामले में यह चलने का कारण यह है कि कोई उपज ब्लॉक नहीं है, और इस प्रकार पूरी विधि एक ही समय में चलती है।

इस विशिष्ट मामले में, यह संभव है कि आपको किसी भी लाभ एक नियमित रूप से एक के ऊपर एक iterator ब्लॉक का उपयोग करने के वजह से अपने GetClassesFromDb() नहीं एक या तो है नहीं होगा कि। इसका मतलब यह है कि यह पहली बार सभी डेटा को एक ही समय में पुनर्प्राप्त करेगा। इटरेटर ब्लॉक का सबसे अच्छा उपयोग तब किया जाता है जब आप एक समय में आइटम एक्सेस कर सकते हैं, क्योंकि अगर आपको अब उनकी आवश्यकता नहीं है तो आप इसे रोक सकते हैं।

0

मुझे एक बेहद विनाशकारी तरीके से सीखना था कि कितना ठंडा/खतरनाक yield है जब मैंने अपनी कंपनी के पार्सर को आने वाले डेटा को आलसी तरीके से पढ़ने का फैसला किया। सौभाग्य से हमारे कार्यान्वयन कार्यों के कुछ हद तक वास्तव में केवल उपज कीवर्ड का उपयोग किया जाता है। कुछ दिनों के लिए यह महसूस करने के लिए लगा कि यह चुपचाप कोई काम नहीं कर रहा था।

उपज कीवर्ड यह के रूप में यह संभवतः पूरी तरह पद्धति पर लंघन अगर आप .ToList() या .FirstOrDefault() या .Any()

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

public class WhatDoesYieldDo 
{ 
    public List<string> YieldTestResults; 

    public List<string> ListTestResults; 

    [TestMethod] 
    public void TestMethod1() 
    { 
     ListTest(); 
     Assert.IsTrue(ListTestResults.Any()); 

     YieldTest(); 
     Assert.IsTrue(YieldTestResults.Any()); 
    } 

    public IEnumerable<string> YieldTest() 
    { 
     YieldTestResults = new List<string>(); 
     for (var i = 0; i < 10; i++) 
     { 
      YieldTestResults.Add(i.ToString(CultureInfo.InvariantCulture)); 
      yield return i.ToString(CultureInfo.InvariantCulture); 
     } 
    } 

    public IEnumerable<string> ListTest() 
    { 
     ListTestResults = new List<string>(); 

     for (var i = 0; i < 10; i++) 
     { 
      ListTestResults.Add(i.ToString(CultureInfo.InvariantCulture)); 
     } 

     return ListTestResults; 
    } 
} 

कहानी का नैतिक: यह सुनिश्चित करें कि यदि एक विधि है कि IEnumerable देता है और आप उस विधि में yield उपयोग करते हैं, आप कुछ है कि परिणामों पर पुनरावृति जाएगा, या विधि बिल्कुल पर अमल नहीं होगा किया हुआ है।

संबंधित मुद्दे