2011-07-04 16 views
21

foreachステートメントを扱うときにC#コンパイラを使用する"Pattern-based" approachをよく理解しています。なぜforeach文でC#コンパイラが文字列クラスを扱うのですか

およびC#言語仕様(セクション8.8.4)からは、すべてのC#コンパイラの最初GetEnumerator方法を見つけようとするだけにしIEnumerable<T>IEnumerableインターフェイスを見つけようとすることは明らかです。

しかし、なぜC#コンパイラの扱い別途string、私のためにその不明確(StringクラスはCharEnumeratorを返し、それはまたIEnumerable<char>IEnumerable interfcesを実装する方法GetEnumeratorが含まれているため):

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クラスに関する言語仕様の例外を見つけることができません。誰かがこの解決策についていくつかの洞察を与えることができますか?

私はC#4コンパイラを試しました。前のコードスニペットのILコードは次のとおりです。

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

私の推測では、Stringクラス(またはいくつかのレガシーコード)の内部最適化だと思います。コンパイラをビルドするときは、内部クラスに必要な方法を選択できます。 – 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

ありがとう、Ani。あなたは説明が妥当と思われます。 –

関連する問題