Přejít na obsah|Přejít k hlavnímu menu|Přejít k vyhledávání

edhouse-CookieGdpr-Policy-s
1073043
0
/cz/gdpr/
208650B6B

Zpět na Blog

NávodyVzdělávání

Imutabilní kolekce v C#: na co si dát pozor?

29.9.2026Filip Kubíček

S imutabilními kolekcemi se v C# setkáváme poměrně často, ale často si neuvědomujeme všechny možnosti, které máme, v čem přesně se liší, a jak vybrat tu správnou v daný moment.

Imutabilní – neboli neměnné – kolekce a kolekce pouze pro čtení působí na první pohled jako jednoduchý koncept. Stačí si představit např. seznam nebo slovník, jehož prvky nelze přidávat ani odebírat, pouze číst.

K čemu je to ale dobré?

Při zodpovídání této otázky zjistíme, že C# nabízí několik typů imutabilních či read-only kolekcí a odpověď záleží na širším kontextu. Pokud chceme psát kvalitní kód, je dobré se v dostupných možnostech vyznat a umět zvolit tu správnou. Pojďme se na ně podívat.

Rozhraní IReadOnly: pouze pro čtení na oko

S touto skupinou se vývojáři většinou setkají jako první. Jde o rozhraní jako IReadOnlyList<T>, IReadOnlyCollection<T> nebo IReadOnlyDictionary<TKey, TValue>.

Tato rozhraní obsahují podmnožinu metod klasických kolekcí - chybí právě ty metody, kterými lze kolekce měnit.

List<string> names = ["Ada", "Grace"];

IReadOnlyList<string> roNames = names;

Kód pracující s proměnnou roNames nemůže volat metody jako Add, Remove a Clear. To je pro vývojáře užitečný signál a zároveň vynucená kontrola.

Garance imutability je však pouze kosmetická. Kód pracující s původní referencí names může změny provádět libovolně. Obě reference ukazují na tentýž objekt, změna se tedy projeví i v roNames.

Referenci roNames je dokonce možné přetypovat zpět na List<string> a provést změnu. Tímto explicitním porušením kontraktu si však vývojář již v podstatě říká o problémy.

Přestože jsou rozhraní ze skupiny IReadOnly pouze pro čtení spíše na oko, jde o velmi užitečný mechanismus. Jeho využívání téměř nic nestojí a hlavními benefity jsou zpřehlednění kódu a zamezení mutaci kolekce omylem. Ve většině základních případů je to přesně to, co potřebujeme.

Třídy ReadOnly: opět jen na oko

Pro úplnost uveďme, že stejný princip platí i pro podobnou skupinu tříd zahrnující např. ReadOnlyCollection<T>, ReadOnlyDictionary<TKey,TValue> a ReadOnlySet<T>.

ReadOnlyCollection<string> rocNames = names.AsReadOnly();

Podobně jako rozhraní skupiny IReadOnly jsou i třídy skupiny ReadOnly jen jakýmsi obalem nad původní referencí. Skrz tento obal nelze kolekci upravovat, protože chybí mutační metody. Ale pod obalem se skrývá klasický mutovatelný objekt.

Immutable: opravdová imutabilita

Co kdybychom místo pouhé reference pouze pro čtení chtěli skutečně imutabilní kolekci?

Intuitivně bychom mohli sáhnout po třídách jako ImmutableList<T>, ImmutableDictionary<TKey, TValue>, ImmutableHashSet<T> a dalších. Instance těchto tříd jsou skutečně imutabilní.

IImmutableList<string> fruits = ImmutableList.Create("kiwi", "mango");

Takto vzniklý objekt bude vždy obsahovat právě řetězce kiwi a mango, nehledě na to, kolik referencí na něj vytvoříme a co s nimi budeme dělat.

Jaké benefity tato garance přináší? Tady je potřeba dát pozor na to, k čemu třídy skupiny Immutable ve skutečnosti slouží.

Při práci s imutabilními kolekcemi nejde o to, že se data vůbec nemění. Nesmí se měnit v rámci konkrétního objektu. Pokud chceme kolekci, která například obsahuje jeden prvek navíc, je nutné vytvořit kolekci novou jako kopii původní s naší změnou:

IImmutableList<string> fruitsAndVegetables = fruits.Add("carrot");

Podstata Immutable tříd spočívá v tom, že v tomto okamžiku nedochází ke kopírování celé původní kolekce. Vtip je v tom, že na pozadí se využívá mechanismus sdílené paměti, který dovoluje novému objektu efektivně využít neměnná data původní kolekce.

To přináší klíčovou úsporu paměti v situaci, kdy je původní kolekce velká. Změny lze navíc transparentně řetězit.

IImmutableList<string> fruitsAndVegetablesAndMeat = fruitsAndVegetables.Add("beef");

Kvůli tomuto mechanismu může být čtení z těchto imutabilních kolekcí pomalejší. Tento kompromis má své opodstatnění. Efektivní vytvoření kopie se změnou při zachování imutability původního objektu je klíčové pro některé styly programování – zejména funkcionální programování – a může účinně zmenšit komplexitu paralelních programů.

Frozen: vytvořit jednou, číst mnohokrát

V případě, že chceme imutabilní kolekci skutečně optimalizovanou pro čtení, můžeme od verze .NET 8 sáhnout po FrozenDictionary<TKey,TValue> a FrozenSet<T>.

FrozenSet<string> colors = new HashSet<string> { "yellow", "green" }.ToFrozenSet();

Takto vzniklá "zamrzlá" kolekce nabízí rychlé operace pro čtení. To se hodí v případě velké kolekce a častého přístupu k datům v ní. Cenou za tuto optimalizaci je pomalejší vytvoření takové kolekce. Při vytváření jsou totiž data kolekce analyzována a je pro ně vypočítána struktura umožňující právě ono rychlé čtení.

Háček na závěr

Imutabilní kolekce mají ještě jeden háček: jejich garance se vztahuje pouze na strukturu kolekce. Pokud kolekce obsahuje mutovatelné objekty, jejich data se mohou nadále měnit. Řešení je zřejmé - pokud na tom záleží, je nutné použít imutabilní objekty.

Kterou vybrat?

Na závěr si zopakujme možnosti, které nám C# nabízí:

  • Rozhraní IReadOnly využijeme běžně v kódu, když chceme vyjádřit, že se daná kolekce nemá měnit.
  • Třídy Immutable jsou užitečné, pokud potřebujeme vytvářet změny bez modifikace původní instance kolekce.
  • Třídy Frozen se hodí, pokud chceme optimalizovat čtení z kolekce za cenu jejího pomalejšího vytvoření a ztráty možnosti ji upravovat.

Já osobně v kódu často používám rozhraní IReadOnly. Naproti tomu třídy Immutable a Frozen se hodí spíše ve specifických situacích. Je však užitečné znát jejich vlastnosti nejen pro případy, kdy je jejich použití na místě, ale i proto, abychom se vyhnuli jejich nesprávnému použití.

Sdílet článek

Autor

Filip Kubíček

Filip KubíčekBackend developer primárně v .NET, baví mě i Go a DevOps. Ve volnu cyklistika, voda a hraní si s technologiemi.

Edhouse newsletter

Získejte aktuální info ze světa Edhouse - novinky, setkávání, aktuální trendy softwarové i hardwarové.

Registrací vyjadřujete souhlas se zpracováním osobních údajů.

Děkujeme za váš zájem o odběr našeho newsletteru! Pro dokončení registrace je potřeba potvrdit vaše přihlášení. Na zadaný e-mail jsme vám právě zaslali potvrzovací odkaz. Klikněte prosím na tento odkaz, aby bylo vaše přihlášení dokončeno. Pokud e-mail nenajdete, zkontrolujte prosím složku nevyžádané pošty (spam) nebo složku hromadné pošty.