This is a detailed answer关于foreach
是一个可变结构的情况下C#编译器如何优化IEnumerator<T>
。
F#编译器是否执行相同的优化?
答案 0 :(得分:5)
AFAICT似乎F#以与C#类似的方式对待valuetype枚举器:
以下是来自简单C#程序的IL代码的反汇编代码段,该代码使用foreach而不是IEnumerable<T>
.locals init (
[0] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>,
[1] int32 v
)
IL_0025: ldloca.s 0
IL_0027: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
请注意local 0
是一个值类型,它使用ldloca.s
来加载结构的地址。
将其与F#进行比较
.locals init (
[0] class [mscorlib]System.Collections.Generic.List`1<int32> ra,
[1] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
)
IL_000e: ldloca.s 1
IL_0010: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
此代码还使用valuetype声明local 1
和ldloca.s
来加载结构的地址。
作为旁注:后来F#版本确实进行了C#不做的优化。因为F#中的常见模式是迭代不可变数据结构的F#列表,所以使用枚举器进行迭代是无效的。所以F#有一个列表的特殊情况,在这种情况下应用更有效的算法。在C#中迭代F#列表将回退到枚举器。
也可以为IList
类型实现特殊处理,但由于有可能某人以“有趣”的方式实现IList
,因此实施此类优化可能会发生重大变化。