2008-09-25 10 views
29

मुझे इसे स्वयं समझना अच्छा लगेगा लेकिन मैं सोच रहा था कि मोटे तौर पर एक गणनाकर्ता के लिए एक राज्य मशीन में उपज बयान के साथ एक समारोह को परिवर्तित करने के लिए एल्गोरिदम क्या है? इस मेंसी # उपज कथन लागू करने के लिए एल्गोरिदम

IEnumerator<string> strings(IEnumerable<string> args) 
{ IEnumerator<string> enumerator2 = getAnotherEnumerator();  
    foreach(var arg in arg) 
    { enumerator2.MoveNext(); 
     yield return arg+enumerator.Current; 
    } 
} 

: उदाहरण कैसे करता है के लिए सी # इस बारी

bool MoveNext() 
{ switch (this.state) 
    { 
     case 0: 
      this.state = -1; 
      this.enumerator2 = getAnotherEnumerator(); 
      this.argsEnumerator = this.args.GetEnumerator(); 
      this.state = 1; 
      while (this.argsEnumerator.MoveNext()) 
      { 
       this.arg = this.argsEnumerator.Current; 
       this.enumerator2.MoveNext(); 
       this.current = this.arg + this.enumerator2.Current; 
       this.state = 2; 
       return true; 

       state1: 
       this.state = 1; 
      } 
      this.state = -1; 
      if (this.argsEnumerator != null) this.argsEnumerator.Dispose(); 
      break; 

     case 2: 
      goto state1; 
    } 
    return false; 
} 

बेशक परिणाम मूल कोड के आधार पर पूरी तरह से अलग हो सकता है।

उत्तर

58

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

var enumerator = y.GetEnumerator(); 
while (enumerator.MoveNext()) 
{ 
    var x = enumerator.Current; 
    //body 
} 

if (y != null) 
{ 
    enumerator.Dispose(); 
} 

दूसरा परिवर्तन समारोह शरीर में सभी उपज वापसी बयान पाता है: इस कोड में

foreach (var x in y) 
{ 
    //body 
} 

:

पहले परिवर्तन "foreach" परिवर्तन है, जो इस कोड को बदल देती है , प्रत्येक (एक राज्य मूल्य) के लिए एक संख्या निर्दिष्ट करता है, और उपज के ठीक बाद एक "गोटो लेबल" बनाता है।

तीसरा परिवर्तन विधि निकाय में सभी स्थानीय चर और कार्य तर्क को बंद करने वाले ऑब्जेक्ट में ले जाता है।

अपने उदाहरण में कोड को देखते हुए कि इस के समान दिखेगा:

class ClosureEnumerable : IEnumerable<string> 
{ 
    private IEnumerable<string> args; 
    private ClassType originalThis; 
    public ClosureEnumerator(ClassType origThis, IEnumerable<string> args) 
    { 
     this.args = args; 
     this.origianlThis = origThis; 
    } 
    public IEnumerator<string> GetEnumerator() 
    { 
     return new Closure(origThis, args); 
    } 
} 

class Closure : IEnumerator<string> 
{ 
    public Closure(ClassType originalThis, IEnumerable<string> args) 
    { 
     state = 0; 
     this.args = args; 
     this.originalThis = originalThis; 
    } 

    private IEnumerable<string> args; 
    private IEnumerator<string> enumerator2; 
    private IEnumerator<string> argEnumerator; 

    //- Here ClassType is the type of the object that contained the method 
    // This may be optimized away if the method does not access any 
    // class members 
    private ClassType originalThis; 

    //This holds the state value. 
    private int state; 
    //The current value to return 
    private string currentValue; 

    public string Current 
    { 
     get 
     { 
      return currentValue; 
     } 
    } 
} 

विधि शरीर फिर मूल विधि से ले जाया जाता है "बंद" के अंदर एक विधि MoveNext कहा जाता है, जो एक bool रिटर्न के लिए , और IENumerable.MoveNext लागू करता है। किसी भी स्थानीय लोगों के लिए किसी भी पहुंच को "इस" के माध्यम से भेजा जाता है, और किसी भी वर्ग के सदस्यों के लिए किसी भी पहुंच को इस माध्यम से रूट किया जाता है।

किसी भी "उपज वापसी expr" में अनुवाद किया है:

state = -1; 
return false; 

एक "निहित" के अंत में उपज तोड़ बयान नहीं है:

currentValue = expr; 
state = //the state number of the yield statement; 
return true; 

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

मूल विधि तो कुछ इस तरह में अनुवाद किया जाता है:

IEnumerator<string> strings(IEnumerable<string> args) 
{ 
    return new ClosureEnumerable(this,args); 
} 

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

हालांकि, यह इंगित करना महत्वपूर्ण है कि सी # कंपाइलर द्वारा उपयोग किया जाने वाला परिवर्तन ऐसा करने का सबसे अच्छा तरीका नहीं है। रिकर्सिव एल्गोरिदम के साथ "उपज" का उपयोग करने की कोशिश करते समय यह खराब प्रदर्शन से पीड़ित है।

http://research.microsoft.com/en-us/projects/specsharp/iterators.pdf

यह यदि आप इसे अभी तक नहीं पढ़ा है पढ़ने लायक है: वहाँ एक अच्छा कागज कि इस यहाँ करने के लिए एक बेहतर तरीका की रूपरेखा है।

+2

वाह। उत्कृष्ट और व्यापक उत्तर। काश मैं इसे एक से अधिक बार वोट दे सकता हूं। –

7

रेमंड चेन इसका उत्तर देते हैं; http://blogs.msdn.com/b/oldnewthing/archive/2008/08/12/8849519.aspx

+1

रेमंड चेन बस कहता है कि "यह जादू है" –

+0

मुझे लगता है कि मार्क्सिडाड यह समझना चाहता है कि संकलक द्वारा व्याख्या और परिवर्तन करने के लिए उपयोग किए गए एल्गोरिदम क्या है आई # में इटरेटर ब्लॉक के सी # कोड जो एक राज्य मशीन के अनुरूप है। –

+0

हाँ रोमेन सही है –

7

हाल ही में इस प्रश्न को देखा - I wrote an article। मुझे यहां लेख में उल्लिखित अन्य लिंक जोड़ना होगा ...

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