2013-10-09 37 views
2

哪种方法更快或者是否都编译为相同的IL?Foreach循环,在循环语句之外派生迭代集合会更快吗?

 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 
     } 

回答

2

推出模式都产生相同的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 
} 

如可以看到的调用不同处于* L_0008 *和无码跳转有或以上这意味着它只被称为一次。

+0

在IL中,无论迭代次数如何,调试模式下的额外赋值都会进行一次? –

+0

是的,它将* myCollection.Values.Distinct()*的值存储在堆栈上,而无需再次调用该方法。 – Elisha

+0

非常感谢... –