Foreach vs. Enumerator
Jorrit Postma maakte de opmerking in een discusie dat een foreach kostbaarder zou zijn dan het zelf door een enumerator lopen.
Ik wou dit niet geloven en ben is gaan kijken wat voor MSIL code er word geproduceerd.
Als we devolgende code pakken met een foreach:
En devolgende code met een IEnumerator:
Resulteerd dit in bijde bevallen devolgende MSIL:
Dus een foreach of zelf door een enumerator heenlopen maakt kwa preformens geen verschil, maar voor leesbaarheid wel. Een foreach is leesbaarder en is niet duurder.
Ik wou dit niet geloven en ben is gaan kijken wat voor MSIL code er word geproduceerd.
Als we devolgende code pakken met een foreach:
[STAThread]
static void Main(string[] args)
{
foreach(string arg in args)
{
Console.WriteLine( arg );
}
}
En devolgende code met een IEnumerator:
[STAThread]
static void Main(string[] args)
{
IEnumerator enumerator = args.GetEnumerator();
while(enumerator.MoveNext())
{
Console.WriteLine( enumerator.Current );
}
}
Resulteerd dit in bijde bevallen devolgende MSIL:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 27 (0x1b)
.maxstack 2
.locals init ([0] string arg,
[1] string[] CS$00000007$00000000,
[2] int32 CS$00000008$00000001)
IL_0000: ldarg.0
IL_0001: stloc.1
IL_0002: ldc.i4.0
IL_0003: stloc.2
IL_0004: br.s IL_0014
IL_0006: ldloc.1
IL_0007: ldloc.2
IL_0008: ldelem.ref
IL_0009: stloc.0
IL_000a: ldloc.0
IL_000b: call void [mscorlib]System.Console::WriteLine(string)
IL_0010: ldloc.2
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: ldloc.1
IL_0016: ldlen
IL_0017: conv.i4
IL_0018: blt.s IL_0006
IL_001a: ret
} // end of method Class1::Main
Dus een foreach of zelf door een enumerator heenlopen maakt kwa preformens geen verschil, maar voor leesbaarheid wel. Een foreach is leesbaarder en is niet duurder.

3 Comments:
Een foreach is niets meer dan een facade voor precies die code: een enumerator ophalen en een while loopje erover doen.
Wat volgens mij wel verschil maakt is of je een foreach doet of een 'gewone' for (for (int i; i<10; i++))... die laatste schijnt sneller te zijn, maar leesbaarheid is wat mij betreft ook een groter goed dan dit soort minimale performance verschillen.
By
Dick Appel, at 9:04 AM
Een foreach of een for hangt weer af van wat je met je object doet binnen de collection. Ga je deze alsnog gebruiken dan is een foreach sneller.
Misschien toch is leuk om hier is een benchmarkje voor te schrijven, want op Codeproject staan verschilllende beweringen.
By
PJ. van de Sande, at 11:37 AM
Dit resultaat vind ik niet opmerkelijk.
Foreach maakt immers gebruik van GetEnumerator. Wat mij wel verbaasd in de reactie van Dick Appel, is dat for sneller schijnt te zijn dan foreach. Hier declareer je immers een extra variabele (de integer). Daar komt nog bij dat niet iedere class met IEnumerator een self-index (of hoe heet dat) heeft.
Op deze pagina wordt aangegeven dat foreach en for dezelfde MSIL produceren.
even offtopic, fijn weer wat van je te lezen Joost!
By
Richard Tuin, at 11:45 AM
Post a Comment
<< Home