今天偶然与建议不要用for,可读性太差性能又低,可我个人认为要根据具体情况而定,毕竟for在大部分语言的关键字,可读性不可能因为一个关键字的替代而变好,多数取决于设计和编码习惯。
至于性能,打算写段代码对它们分别测试一下。
var arr = enumerable.range(0, 100000000).tolist();
var sw = stopwatch.startnew();
for(var i = 0;i < arr.count; i++){}
sw.stop();
console.writeline("for loop takes : " + sw.elapsedticks);
sw = stopwatch.startnew();
foreach(var x in arr){}
sw.stop();
console.writeline("for loop takes : " + sw.elapsedticks);
先看生成的il
for循环的部分:
...
il_0018: ldc.i4.0
il_0019: stloc.2 // i
il_001a: br.s il_0022
il_001c: nop
il_001d: nop
il_001e: ldloc.2 // i
il_001f: ldc.i4.1
il_0020: add
il_0021: stloc.2 // i
il_0022: ldloc.2 // i
il_0023: ldloc.0 // arr
il_0024: callvirt system.collections.generic.list<system.int32>.get_count
il_0029: clt
il_002b: stloc.s 04 // cs$4$0000
il_002d: ldloc.s 04 // cs$4$0000
il_002f: brtrue.s il_001c
...
除了il_0024中的callvirt会触发方法虚表查询外,几乎不存在任何高消耗的指令。再来看foreach的il部分:
...
il_005a: ldloc.0 // arr
il_005b: callvirt system.collections.generic.list<system.int32>.getenumerator
il_0060: stloc.s 05 // cs$5$0001
il_0062: br.s il_006e
il_0064: ldloca.s 05 // cs$5$0001
il_0066: call system.collections.generic.list<system.int32>+enumerator.get_current
il_006b: stloc.3 // x
il_006c: nop
il_006d: nop
il_006e: ldloca.s 05 // cs$5$0001
il_0070: call system.collections.generic.list<system.int32>+enumerator.movenext
il_0075: stloc.s 04 // cs$4$0000
il_0077: ldloc.s 04 // cs$4$0000
il_0079: brtrue.s il_0064
il_007b: leave.s il_008c
il_007d: ldloca.s 05 // cs$5$0001
il_007f: constrained. system.collections.generic.list<>.enumerator
il_0085: callvirt system.idisposable.dispose
il_008a: nop
il_008b: endfinally
il_008c: nop
...
首先可以看到很多方法调用,并且在循环体内部每次都要调用方法movenext。最后可以看到,有end finally,意味着这个循环外部包了一层try-finally。从il来看,foreach要比for慢的多了。
现在来看stopwatch的执行结果。
for loop takes : 764538
for loop takes : 1311252
for几乎快了一倍。
结论:编程语言提供的关键字是为了解决某种问题而存在,需要对具体的业务场景进行判断再决定,有关性能方面,一定要拿出数据说话。
以上就是c#, for vs foreach的内容。