arckép

Neuwirth István

programtervező informatikus MSc – ELTE

Computational and Software Techniques MSc – Cranfield, UK

Elérhetőség
pitta2@gmail.com
+36 30 329 3039

Valid XHTML 1.0 Transitional

Valid CSS!

Foreach

A több nyelvben is megtalálható foreach szerkezetről

A foreach nyelvi szerkezet egy objektumgyűjtemény elemeinek bejárására szolgál. Megtalálható nyelvi elemként a C#, Java, PHP, Visual Basic és még sok más nyelvben. A következőkben a C# nyelvben betöltött szerepét és a vele kapcsolatos optimalizációs lehetőségeket mutatom be.

A foreach olyan nem indexelhető gyűjtemények bejárására is alkalmas (például halmazok, fák), ahol a for ciklus már nem lenne használható. Fordítva azonban, mint például egy tömb elemein való végiglépkedés esetén használható a foreach is. Előnye a normál for ciklussal szemben az, hogy nem kell nyilvántartanunk a határokat, a gyűjtemény hosszát és így nem fordulhat elő elindexelési probléma, vagy a tömbhatárok szélén eggyel való túllépés, az úgynevezett off-by-one hiba (például for (int i=0; i<=3; ++i) { a[i]… } használata egy 3 elemű tömbre).

A foreach minden olyan osztályra használható, amely megvalósítja az IEnumerable interfészt. Ennek egyetlen GetEnumerator függvénye egy IEnumerator interfészt implementáló objektumot ad vissza. Ez egy bool MoveNext() függvényt és egy void Reset() metódust, illetve egy Current tulajdonságot definiál, így egy while (en.MoveNext()) { en.Current… } ciklussal végigmehetünk a gyűjtemény elemein. Természetesen mindkét interfésznek létezik generikus változata is.

A foreach használata mindenekelőtt biztonságosabb és átláthatóbb programkódot eredményez. Például a C# által nyelvi szinten támogatott többdimenziós tömbök bejárása egymásbaágyazott for ciklusok helyett egyetlen foreach segítségével megtehető. Meglepő mód a C++-ban legoptimálisabb for ciklussal történő tömbbön való végighaladás eredményezi a legrosszabb teljesítményű kódot (lásd a példában). Ekkor ugyanis nem adjuk meg a fordítónak a lehetőséget arra, hogy a ciklustörzsben elhagyja az indexellenőrzéseket és kiemelje a ciklus elé. C# alatt nem tehetjük meg, hogy egy tömb határain kívül indexelünk, ezt a futtatókörnyezet biztosítja. Hibás index alkalmazásakor futásidőben IndexOutOfRangeException típusú kivételt kapunk, ami a ciklus beljesében történő ellenőrzésekkor jöhet létre. Amennyiben a túlindexelés nem fordulhat elő, a fordító elhagyhatja az ellenőrzéseket, optimális kódot állítva elő.

int[] t = new int[1000000];

...
int l = t.Length;
for (int i = 0; i < l; ++i)
{
x += t[i];
}

helyett használjuk az alábbi alakokat:

for (int i = 0; i < t.Length; ++i)
{
x += t[i];
}

vagy

foreach (int y in t)
{
    x += y;
}