2011-07-04 17 views
21

साथ अलग से स्ट्रिंग वर्ग इलाज किया मैं स्पष्ट रूप से "Pattern-based" approach सी # संकलक का उपयोग करता है जब यह foreach बयान के साथ काम को समझते हैं।क्यों सी # संकलक foreach बयान

और से सी # भाषा विशिष्टता (खंड 8.8.4) यह स्पष्ट है सब सी # संकलक की पहली GetEnumerator विधि खोजने की कोशिश करता और उसके बाद ही IEnumerable<T> और IEnumerable इंटरफेस खोजने की कोशिश करता है।

लेकिन, क्यों सी # संकलक string अलग व्यवहार करता है मेरे लिए स्पष्ट नहीं (क्योंकि String वर्ग एक विधि GetEnumerator कि CharEnumerator रिटर्न होता है और यह भी IEnumerable<char> और IEnumerable interfces लागू करता है):

string s = "1234"; 
foreach(char c in s) 
    Console.WriteLine(c); 

में धर्मान्तरित
string s = "1234"; 
for(int i = 0; i < s.Length; i++) 
    Console.WriteLine(s[i]); 

लेकिन मुझे String कक्षा के संबंध में भाषा विशिष्टता में कोई अपवाद नहीं मिल रहा है। क्या कोई इस समाधान के बारे में कुछ अंतर्दृष्टि दे सकता है?

मैंने सी # 4 कंपाइलर के साथ प्रयास किया।

IL_0000: ldstr  "1234" 
IL_0005: stloc.0  
IL_0006: ldloc.0  
IL_0007: stloc.2  
IL_0008: ldc.i4.0  
IL_0009: stloc.3  
IL_000A: br.s  IL_001E 
IL_000C: ldloc.2  
IL_000D: ldloc.3  
IL_000E: callvirt System.String.get_Chars 
IL_0013: stloc.1  
IL_0014: ldloc.1  
IL_0015: call  System.Console.WriteLine 
IL_001A: ldloc.3  
IL_001B: ldc.i4.1  
IL_001C: add   
IL_001D: stloc.3  
IL_001E: ldloc.3  
IL_001F: ldloc.2  
IL_0020: callvirt System.String.get_Length 
IL_0025: blt.s  IL_000C 
+0

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

उत्तर

21

अच्छा पकड़: यहाँ पिछले कोड स्निपेट के लिए आईएल कोड है। मुझे पता था कि कंपाइलर ने सरणी के लिए एक समान अनुकूलन किया था, लेकिन मुझे नहीं पता था कि यह तारों के लिए भी ऐसा करता है।

सबसे अच्छा मैं तुम्हें मिल सकता है

language specification कि एक संकलक 'कैनन' के रूप में लंबे समय से दूर करने के लिए के रूप में यह बराबर व्यवहार का उत्पादन का अधिकार देता है से एक फोन-बाहर है:

8.8.4 foreach बयान

[...] प्रपत्र की एक foreach बयान foreach (V v in x)एम्बेडेड बयान तो करने के लिए विस्तारित किया गया है:

{ 
    E e = ((C)(x)).GetEnumerator(); 
    try { 
     V v; 
     while (e.MoveNext()) { 
      v = (V)(T)e.Current; 
      embedded-statement 
     } 
    } 
    finally { 
     … // Dispose e 
    } 
} 

[...] कार्यान्वयन की अनुमति दी है अलग ढंग से करता है, उदा एक दिया foreach बयान लागू करने के लिए प्रदर्शन कारणों के लिए, जब तक उपरोक्त विस्तार के साथ व्यवहार है।

+0

धन्यवाद, एनी। आप स्पष्टीकरण उचित लगता है। –

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