Rozhraní IEnumerable je základním stavebním kamenem práce s kolekcemi v prostředí .NET. Definuje mechanismus, který umožňuje procházet prvky kolekce jeden po druhém, aniž by bylo nutné znát konkrétní způsob uložení dat v kolekci. Toto je realizováno s využitím enumerátoru.
IEnumerable i IEnumerator mají generickou i konkrétní variantu. Generická se nachází v namespace System.Collections.Generic;
IEnumerator
Enumerator je objekt, který umožňuje procházet (iterovat) prvky kolekce jednu položku po druhé. Slouží jako prostředník mezi kolekcí a kódem, který ji chce procházet.
Enumerator poskytuje tři klíčové členy:
- MoveNext() – posune enumerátor na další prvek v kolekci. Vrací
true, pokud existuje další prvek, nebofalse, pokud kolekce skončila. - Current – vrací aktuální prvek kolekce. Volání je platné pouze tehdy, pokud se enumerátor nachází na platné pozici (tedy po úspěšném
MoveNext()). - Reset() – nastaví enumerátor před první prvek kolekce. Tato metoda není vždy implementována a nemusí být podporována u všech kolekcí.
Příklad použití enumerátoru bez foreach:
IEnumerable<int> cisla = new List<int> { 10, 20, 30 };
using IEnumerator<int> enumerator = cisla.GetEnumerator();
while (enumerator.MoveNext())
{
int prvek = enumerator.Current;
Console.WriteLine(prvek);
}Využití IEnumerable
- Iterace – umožňuje používat konstrukce jako
foreach, které skrývají detaily voláníGetEnumerator()aMoveNext(). - Zřetězení operací – metody LINQ (například
Where,Select,OrderBy) vracejí opětIEnumerable<T>, což umožňuje řetězit více operací za sebou. - Zpožděné vyhodnocení (deferred execution) – operace nad
IEnumerablečasto nejsou vykonány ihned, ale až ve chvíli, kdy se začnou skutečně číst výsledky kolekce (například vforeach). To umožňuje úsporu paměti a lepší výkon.
Fungování operací nad IEnumerable
Pokud se nad objektem typu IEnumerable volají metody jako Where, Select nebo další LINQ operace, nevytváří se ihned nová kolekce. Místo toho se vytváří „výpočetní řetězec“, který se provede až v okamžiku, kdy je potřeba získat data. Tento princip se nazývá zpožděné vyhodnocení (deferred execution).
using System.Linq;
using System.Collections.Generic;
// Vygenerování prvků od 1 do 10 a uložení
IEnumerable<int> cisla = Enumerable.Range(1, 10);
// V tuto chvíli se nic nevyhodnocuje
var sude = cisla.Where(x => x % 2 == 0);
// Vyhodnocení proběhne až zde - je nutné získat obsah proměnné "sude"
foreach (var cislo in sude)
{
Console.WriteLine(cislo);
}