2012-02-10 7 views
8

मैं पहले कुछ कोड रीफैक्टर कर रहा था और मैं एक इटरेटर ब्लॉक के कार्यान्वयन में आया था, जिसके बारे में मुझे यकीन नहीं था। एक सिस्टम की एकीकरण परत में जहां क्लाइंट कुछ डेटा के लिए एक्स्ट्राइनल एपीआई को कॉल कर रहा है, मेरे पास अनुवादकों का एक सेट है जो एपीआई से वापस डेटा लेते हैं और इसे तर्क परत में उपयोग की जाने वाली व्यावसायिक संस्थाओं के संग्रह में अनुवाद करते हैं। एक आम अनुवादक वर्ग इस तरह दिखेगा:इटेटरेटर ब्लॉक का सही उपयोग

// translate a collection of entities coming back from an extrernal source into business entities 
public static IEnumerable<MyBusinessEnt> Translate(IEnumerable<My3rdPartyEnt> ents) { 

    // for each 3rd party ent, create business ent and return collection 
    return from ent in ents 
      select new MyBusinessEnt { 
       Id = ent.Id, 
       Code = ent.Code 
      }; 
} 

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

// same implementation of a translator but as an iterator block 
public static IEnumerable<MyBusinessEnt> Translate(IEnumerable<My3rdPartyEnt> ents) { 
    foreach(var ent in ents) 
    { 
     yield return new MyBusinessEnt { 
      Id = ent.Id, 
      Code = ent.Code 
     }; 
    } 
} 

मेरा प्रश्न है: इस पुनरावर्तक ब्लॉक के एक वैध उपयोग है? मैं इस तरह से एक अनुवादक वर्ग बनाने का लाभ नहीं देख सकता। क्या इसका परिणाम कुछ अप्रत्याशित व्यवहार में हो सकता है?

+0

मेरे लिए पूरी तरह से मान्य लगता है- यह दो इकाइयों के बीच संकलन-सुरक्षित अनुवाद प्रदान करता है।इसके साथ समस्या क्या है? –

उत्तर

13

आपके दो नमूने बिल्कुल वही काम करते हैं। क्वेरी संस्करण को कॉल करने के लिए कॉल में फिर से लिखा जाएगा, और चयन आपके दूसरे उदाहरण की तरह लिखा गया है; यह स्रोत संग्रह में प्रत्येक तत्व पर पुनरावृत्ति करता है और उपज-एक रूपांतरित तत्व लौटाता है।

यह हालांकि निश्चित रूप से यह अब आवश्यक है इस तरह अपने खुद के iterator ब्लॉक लिखने के लिए, क्योंकि आप बस Select उपयोग कर सकते हैं, पुनरावर्तक ब्लॉक की एक पूरी तरह से वैध इस्तेमाल होता है।

+0

शानदार - स्पष्टीकरण के लिए धन्यवाद। –

3

हाँ, यह मान्य है। foreach को डिबग करने योग्य होने का लाभ है, इसलिए मैं उस डिज़ाइन को पसंद करता हूं।

+0

तो इटेटरेटर ब्लॉक सिस्टम में बाद में व्यवसाय संस्थाओं के इस संग्रह पर किसी भी प्रस्ताव को डीबग करने का प्रयास करने वाले किसी भी भ्रम का कारण बन सकता है? –

+1

मुझे नहीं लगता कि जरूरी कोई भ्रम है; 'foreach' ब्लॉक बस अनुवाद किए जा रहे लाइन आइटम को लक्षित करना आसान बनाता है। यदि अनुवाद कभी भी तुच्छ से अधिक हो जाता है तो यह अधिक सरल डिबगिंग की अनुमति देता है। यद्यपि दोनों पूरी तरह से कार्यान्वयन मिल रहे हैं। – eouw0o83hf

3

पहला उदाहरण एक पुनरावर्तक नहीं है। यह सिर्फ IEnumerable<MyBusinessEnt> बनाता है और देता है।

दूसरा एक पुनरावर्तक है और मुझे इसके साथ कुछ भी गलत नहीं दिख रहा है। प्रत्येक बार कॉलर उस विधि के वापसी मूल्य पर पुनरावृत्ति करता है, yield एक नया तत्व लौटाएगा।

-1

प्रमुख अंतरपर प्रत्येक कोड चलाता है। पहला व्यक्ति देरी हो जाता है जब तक कि रिटर्न वैल्यू पुनरावृत्ति न हो जाए, जबकि दूसरा तुरंत चलाता है। मेरा मतलब यह है कि लूप के लिए पुनरावृत्ति को चलाने के लिए मजबूर कर रहा है। तथ्य यह है कि कक्षा IEnumerable<T> का खुलासा करती है और इस मामले में देरी हो रही है एक और बात है।

यह सरल Select पर कोई लाभ नहीं प्रदान करता है। yield की वास्तविक शक्ति है जब वहाँ एक सशर्त शामिल है:

foreach(var ent in ents) 
{ 
    if(someCondition) 
    yield return new MyBusinessEnt { 
     Id = ent.Id, 
     Code = ent.Code 
    }; 
} 
+6

अच्छी तरह से एक मिनट पर पकड़ें - आपका संस्करण किसी साधारण * कहां * के बाद * चयन * पर कोई लाभ नहीं प्रदान करता है। और हाँ, क्रिस दोस्तों की टिप्पणी सही है; दोनों निष्पादन निष्पादन। –

+0

@EricLippert हाँ क्योंकि वह एक लूप का उपयोग कर रहा है और चयन नहीं कर रहा है। लेकिन जैसा कि मैंने कहा, मैं इस मामले में सिर्फ सादे लिंक का उपयोग करूंगा। – Aliostad

+0

क्या आप इस बारे में निश्चित हैं? मैंने सोचा कि दोनों ने मांग पर अपने मूल्यों को प्रभावी ढंग से बनाया - यानी दूसरा दूसरा तुरंत नहीं चलता है। – Chris

3

हां, यह ठीक काम करता है, और परिणाम बहुत समान है।

दोनों एक ऑब्जेक्ट बनाता है जो परिणाम लौटने में सक्षम है। दोनों परिणाम पूरा होने तक बरकरार रहने के लिए समृद्ध स्रोत पर भरोसा करते हैं (या कम कटौती)। दोनों स्थगित निष्पादन का उपयोग करते हैं, यानी वस्तुओं को एक समय में बनाया जाता है जब आप परिणाम को पुन: उत्पन्न करते हैं।

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

+0

ठीक है, लेकिन इस उदाहरण में कस्टम इटरेटर बनाने की कोई ज़रूरत नहीं है? जैसा कि @ एलीओस्टैड ने इंगित किया है, इटेटरेटर ब्लॉक को सशर्त के साथ सबसे अच्छा उपयोग किया जाता है। तो शायद दूसरी विधि थोड़ा कम पठनीय \ डिबगबल है और इसलिए शायद पहला दृष्टिकोण इस परिदृश्य के लिए बेहतर होगा। –

+0

भी अंतर यह है कि कस्टम एन्यूमरेटर तुरंत चलाता है जबकि पहले ('इसे से चुनें') चल रहा है। – Aliostad

+0

@Aliostad - कि, मैं काफी समझ में नहीं आता ... इसलिए पहला उदाहरण एक संग्रह देता है जिसे अभी तक समझा नहीं गया है। दूसरी बार प्रत्येक बार इसे कॉल करने पर रिटर्न संग्रह की गणना करनी है? क्या वो सही है? –