我清楚地理解在处理语句时使用C#编译器的"基于模式"的方法foreach.
从C#语言规范(第8.8.4节)可以看出,首先C#编译器尝试查找GetEnumerator方法,然后才尝试查找IEnumerable<T>和IEnumerable接口.
但我不清楚,为什么C#编译器string单独处理(因为String该类包含一个GetEnumerator返回的方法,CharEnumerator它也实现IEnumerable<char>和IEnumerable交互):
string s = "1234";
foreach(char c in s)
Console.WriteLine(c);
Run Code Online (Sandbox Code Playgroud)
转换为
string s = "1234";
for(int i = 0; i < s.Length; i++)
Console.WriteLine(s[i]);
Run Code Online (Sandbox Code Playgroud)
但我在语言规范中找不到关于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
Run Code Online (Sandbox Code Playgroud)
Ani*_*Ani 21
接得好.我知道编译器对数组执行了类似的优化,但我不知道它也是为字符串执行此操作.
我能得到的最好的是来自语言规范的调出,它使编译器有权偏离'canon',只要它产生相同的行为:
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
}
}
Run Code Online (Sandbox Code Playgroud)
[...] 允许实现以不同方式实现给定的foreach语句,例如出于性能原因,只要行为与上述扩展一致即可.