I clearly understand "Pattern-based" approach that uses开发者_运维知识库 C# compiler when it dealing with the foreach
statement.
And from C# Language Specification (section 8.8.4) it is clear that first of all C# compiler tries to find GetEnumerator
method and only then tries to find IEnumerable<T>
and IEnumerable
interfaces.
But its unclear for me, why C# compiler treats string
separately (because the String
class contains a method GetEnumerator
that returns CharEnumerator
and it also implements IEnumerable<char>
and IEnumerable
interfces):
string s = "1234";
foreach(char c in s)
Console.WriteLine(c);
converts to
string s = "1234";
for(int i = 0; i < s.Length; i++)
Console.WriteLine(s[i]);
But I can't find any exceptions in Language Specification regarding the String
class. Could someone give some insights about this solution?
I tried with the C# 4 compiler. Here is the IL code for the previous code snippet:
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
Good catch. I was aware that the compiler performed a similar optimization for arrays, but I didn't know that it did this for strings too.
The best I can get you is a call-out from the language specification that gives a compiler the right to stray from the 'canon' as long as it produces equivalent behaviour:
8.8.4 The foreach statement
[...] A foreach statement of the form
foreach (V v in x)
embedded-statement is then expanded to:
{
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}
[...] An implementation is permitted to implement a given foreach-statement differently, e.g. for performance reasons, as long as the behavior is consistent with the above expansion.
精彩评论