对于每个循环,在循环语句之外派生迭代集合是否更快
本文关键字:循环 集合 迭代 是否 派生 于每个 语句 | 更新日期: 2023-09-27 18:34:29
哪种方法更快,或者两者都编译到同一个IL?
var myCollection = new Dictionary<string, string>(){{"a", "aa"}, {"b", "bb"}, {"c", "bb"}};
foreach (var uniqueItem in myCollection.Values.Distinct())
{
//do something
}
var myCollection = new Dictionary<string, string>() { { "a", "aa" }, { "b", "bb" }, { "c", "bb" } };
var uniqueItems = myCollection.Values.Distinct();
foreach (var uniqueItem in uniqueItems)
{
//do something
}
在发布模式下,两者产生相同的 IL,并且性能将相同(假设以后不使用 uniqueItems 变量(。
在调试中,您将在开始 foreach 之前看到另一个分配。
编辑 - 生成的 IL
private static void V1(Dictionary<string, string> myCollection)
{
foreach (var uniqueItem in myCollection.Values.Distinct())
{
}
}
将编译成:
.method private hidebysig static void V1(class [mscorlib]System.Collections.Generic.Dictionary`2<string, string> myCollection) cil managed
{
.maxstack 2
.locals init (
[0] string uniqueItem,
[1] class [mscorlib]System.Collections.Generic.IEnumerator`1<string> CS$5$0000,
[2] bool CS$4$0001)
L_0000: nop
L_0001: nop
L_0002: ldarg.0
L_0003: callvirt instance class [mscorlib]System.Collections.Generic.Dictionary`2/ValueCollection<!0, !1> [mscorlib]System.Collections.Generic.Dictionary`2<string, string>::get_Values()
L_0008: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Distinct<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
L_000d: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator()
L_0012: stloc.1
L_0013: br.s L_001e
L_0015: ldloc.1
L_0016: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
L_001b: stloc.0
L_001c: nop
L_001d: nop
L_001e: ldloc.1
L_001f: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
L_0024: stloc.2
L_0025: ldloc.2
L_0026: brtrue.s L_0015
L_0028: leave.s L_003a
L_002a: ldloc.1
L_002b: ldnull
L_002c: ceq
L_002e: stloc.2
L_002f: ldloc.2
L_0030: brtrue.s L_0039
L_0032: ldloc.1
L_0033: callvirt instance void [mscorlib]System.IDisposable::Dispose()
L_0038: nop
L_0039: endfinally
L_003a: nop
L_003b: ret
.try L_0013 to L_002a finally handler L_002a to L_003a
}
可以看出,对 distinct 的调用是在 *L_0008* 中,没有代码跳到那里或上面,这意味着它只被调用一次。