为什么C#编译器用foreach语句单独处理字符串类
本文关键字:单独 处理 字符串 语句 foreach 编译器 为什么 | 更新日期: 2023-09-27 18:01:11
我清楚地理解在处理foreach
语句时使用C#编译器的"基于模式"方法。
从C#语言规范(第8.8.4节(可以清楚地看出,首先C#编译器试图找到GetEnumerator
方法,然后才试图找到IEnumerable<T>
和IEnumerable
接口。
但我不清楚为什么C#编译器单独处理string
(因为String
类包含一个返回CharEnumerator
的方法GetEnumerator
,它还实现了IEnumerable<char>
和IEnumerable
接口(:
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
好的捕获。我知道编译器对数组进行了类似的优化,但我不知道它对字符串也这样做了。
我能给你的最好的结果是从语言规范中调用,只要编译器产生等效的行为,它就有权偏离"正典":
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语句不同,例如性能原因,只要行为与上述扩展一致