Nedávno jsem dostal několik otázek ohledně inicializátorů polí a kolekcí v C#. Protože se to může hodit i někomu dalšímu, rozhodl jsem se sepsat odpověď touto formou.
Veškeré informace zmíněné dále jsou platné pro C# verze 3.0 a vyšší.
Pole
Jednorozměrné pole se standardně deklaruje a inicializuje takto:
string[] array = new string[3]; //Pole o třech řetezcích
Hodnoty se přiřazují prostým zápisem na patričný index:
array[0] = "alpha"; array[1] = "bravo"; array[2] = "charlie";
Pomocí inicializátoru pole (array initializer) lze celý předchozí kód zapsat jedním příkazem:
string[] array = new string[3] {"alpha", "bravo", "charlie"}; var array = new string[3] {"alpha", "bravo", "charlie"}; //Alternativa s implicitně typovanou proměnnou
Inicializátor vždy vytvoří pole o stejném počtu prvků, kolik jich je zadáno ve složených závorkách, takže v přechozím příkladu nelze zadat jiné číslo než tři. Počet prvků tedy vůbec není třeba uvádět.
var array = new string[] {"alpha", "bravo", "charlie"}; //Kompilátor ví, že má vytvořit pole o třech prvcích
C# umožňuje tento příkaz dále zjednodušit – kompilátor totiž dokáže odvodit typ pole z typů jsou použitých v inicializátoru, takže nemusíte uvádět ani typ pole:
var array = new[] {"alpha", "bravo", "charlie"}; //Pole řetězců var array = new[] {"alpha", "bravo", new Object()}; //Pole objektů var array = new[] {"alpha", "bravo", 'c'}; //Chyba - žádný "nejlepší" typ ("No best type found for implicitly-typed array")
V posledním případě by kompilátor musel zapouzdřit znak ‘c’ do objektu a vytvořit pole objektů, což raději nechce udělat automaticky. Snadno to ale vyřešíte uvedením typu pole.
Ve zjednodušování lze jít ještě dále a vynechat i operátor new[]
– kompilátor ví, že výstupem inicializátoru bude pole. Nelze ale zároveň deklarovat proměnnou jako var
a nechat kompilátor typ odvodit.
string[] array = {"alpha", "bravo", "charlie"}; //OK var array = {"alpha", "bravo", "charlie"}; //Nelze
Tuto syntaxi je navíc možné použít pouze při deklaraci lokální proměnné nebo pole (field), nemůžete je použít například při definování argumentu metody.
String.Concat( {"a", "b"} ); //Nelze String.Concat( new[] {"a", "b"} ); //OK
Vícerozměrná pole fungují velmi podobně jako jednorozměrná:
string[,] array = { {"a", "b"}, {"c", "d"} }
Stejný inticializátor ale nemůžete použít pro “zubaté” pole (pole polí), vnitřní pole musíte vytvořit pomocí operátoru new
.
string[][] array = { new[] {"a", "b"}, new[] {"c", "d"} }
Kolekce
Podobná podpora pro inicializaci položek je k dispozici pro všechny kolekce – respektive pro všechny typy implementující rozhraní IEnumerable
a poskytující veřejnou metodu Add
. V případě kolekcí je vždy nutné volat konstruktor, ale místo volání Add
stačí zadat hodnoty ve složených závorkách.
var list = new List<string>() { "alpha", "bravo", "charlie" };
Při volání konstruktoru bez parametrů lze kulaté závorky vynechat.
var list = new List<string> { "a", "b", "c" };
Nicméně je možné využít i parametrický konstruktor – následující příklad vytvoří novou instanci s prvky z existující kolekce a pak přidá další prvky v inicializátoru.
var list2 = new List<string>(list) { "d", "e" }; list2.ForEach( s => Console.Write(s)); //Zobrazí "abcde"
Pokud má metoda Add
více parametrů, je třeba je uzavřít do dodatečných složených závorek. Následující kód přidává dvě položky do slovníku.
var dict = new Dictionary<int, string> { { 1, "alpha" }, { 2, "bravo" } };
Každý prvek v inicializátoru může navíc používat jiné přetížení metody Add
, pokud je k dispozici. Například NameValueCollection
(z jmenného prostoru System.Collection.Specialized
) nabízí metody Add(String, String)
a Add(NameValueCollection)
. Inicializátor proměnné nvc2
využívá obě dvě:
NameValueCollection nvc1 = new NameValueCollection { {"a", "b"} }; NameValueCollection nvc2 = new NameValueCollection { {"c", "d"}, nvc1 };
Inicializátory sice nepřináší nic, co by se nedalo napsat jinak, ale díky nim lze psát kratší a přehlednější kód – a to není málo.