17 Polí
17.1 Obecné
Pole je datová struktura, která obsahuje řadu proměnných, ke kterým se přistupuje prostřednictvím vypočítaných indexů. Proměnné obsažené v matici, označované také jako prvky pole, jsou všechny stejného typu a tento typ se nazývá typ prvku pole.
Pole má pořadí, které určuje počet indexů přidružených k jednotlivým prvkům pole. Pořadí matice se také označuje jako dimenze pole. Pole s pořadím jednoho se nazývá jednorozměrné pole. Pole s pořadím, které je větší než jedno, se nazývá multidimenzionální pole. Multidimenzionální pole se často označují jako dvojrozměrná pole, trojrozměrná pole atd. Každá dimenze pole má přidruženou délku, která je celočíselné číslo větší nebo rovno nule. Délky dimenzí nejsou součástí typu pole, ale jsou vytvořeny při vytvoření instance typu pole za běhu. Délka dimenze určuje platný rozsah indexů pro danou dimenzi: Pro dimenzi délky N
mohou indexy být v rozsahu od 0
po N – 1
inkluzivní. Celkový počet prvků v matici je součin délky každé dimenze v matici. Pokud jedna nebo více dimenzí pole má délku nuly, je pole prázdné.
Typ prvku pole může být sám o sobě typ matice (§17.2.1). Taková pole polí se liší od multidimenzionálních polí a lze je použít k reprezentaci "žloutkových polí".
Příklad:
int[][] pascals = { new int[] {1}, new int[] {1, 1}, new int[] {1, 2, 1}, new int[] {1, 3, 3, 1} };
end example
Každý typ matice je referenčním typem (§8.2). Typ prvku pole může být libovolný typ, včetně typů hodnot a typů pole.
17.2 Typy polí
17.2.1 Obecné
Gramatické produkce pro typy polí jsou uvedeny v §8.2.1.
Typ pole se zapíše jako non_array_type následuje jeden nebo více rank_specifiers.
Non_array_type je jakýkoli typ, který není sám o sobě array_type.
Pořadí typu pole je dáno úplně vlevo rank_specifier v array_type: rank_specifier označuje, že pole je matice s pořadím jednoho a počtem,
tokenů v rank_specifier.
Typ prvku typu pole je typ, který je výsledkem odstranění nejvíce vlevo rank_specifier:
- Typ pole formuláře
T[R]
je matice s pořadímR
a typemT
prvku, který není polem . - Typ pole formuláře
T[R][R₁]...[Rₓ]
je matice s pořadímR
a typemT[R₁]...[Rₓ]
prvku .
Rank_specifier s se tedy čte zleva doprava před posledním typem elementu bez pole.
Příklad: Typ
T[][,,][,]
je jednorozměrné pole třírozměrných polí dvourozměrných polí .int
end example
Za běhu může být null
hodnota typu pole nebo odkaz na instanci tohoto typu pole.
Poznámka: Podle pravidel §17.6 může být hodnota také odkazem na kovariantní typ pole. koncová poznámka
17.2.2 Typ System.Array
System.Array
Typ je abstraktní základní typ všech typů pole. Implicitní převod odkazu (§10.2.8) existuje z libovolného typu pole do System.Array
a na jakýkoli typ rozhraní implementovaný System.Array
. Explicitní převod odkazu (§10.3.5) existuje z System.Array
jakéhokoli typu rozhraní implementovaného System.Array
na jakýkoli typ pole. System.Array
není sám o sobě array_type. Spíše je to class_type , ze kterého jsou odvozeny všechny array_types.
Za běhu může být null
hodnota typu System.Array
nebo odkaz na instanci libovolného typu pole.
17.2.3 Matice a obecná rozhraní kolekcí
Jednorozměrné pole T[]
implementuje rozhraní System.Collections.Generic.IList<T>
(IList<T>
zkráceně) a jeho základní rozhraní. Proto existuje implicitní převod ze T[]
základního rozhraní na IList<T>
a jeho základní rozhraní. Kromě toho platí, že pokud existuje implicitní převod odkazu z do té 10.2.8 IList<T>
a existuje implicitní převod odkazu z IList<T>
S[]
a jeho základního rozhraní (§10.2.8).S[]
T
S
Je-li zde explicitní odkaz na S
T
převod, existuje-li explicitní převod odkazu z IList<T>
S[]
a jeho základního rozhraní (§10.3.5).
Podobně jednorozměrné pole T[]
také implementuje rozhraní System.Collections.Generic.IReadOnlyList<T>
(IReadOnlyList<T>
zkráceně) a jeho základní rozhraní. Proto existuje implicitní převod ze T[]
základního rozhraní na IReadOnlyList<T>
a jeho základní rozhraní. Kromě toho platí, že pokud existuje implicitní převod odkazu z do té 10.2.8 IReadOnlyList<T>
a existuje implicitní převod odkazu z IReadOnlyList<T>
S[]
a jeho základního rozhraní (§10.2.8).S[]
T
S
Je-li zde explicitní odkaz na S
T
převod, existuje-li explicitní převod odkazu z IReadOnlyList<T>
S[]
a jeho základního rozhraní (§10.3.5).
Příklad: Příklad:
class Test { static void Main() { string[] sa = new string[5]; object[] oa1 = new object[5]; object[] oa2 = sa; IList<string> lst1 = sa; // Ok IList<string> lst2 = oa1; // Error, cast needed IList<object> lst3 = sa; // Ok IList<object> lst4 = oa1; // Ok IList<string> lst5 = (IList<string>)oa1; // Exception IList<string> lst6 = (IList<string>)oa2; // Ok IReadOnlyList<string> lst7 = sa; // Ok IReadOnlyList<string> lst8 = oa1; // Error, cast needed IReadOnlyList<object> lst9 = sa; // Ok IReadOnlyList<object> lst10 = oa1; // Ok IReadOnlyList<string> lst11 = (IReadOnlyList<string>)oa1; // Exception IReadOnlyList<string> lst12 = (IReadOnlyList<string>)oa2; // Ok } }
Přiřazení
lst2 = oa1
generuje chybu v době kompilace, protože převod zobject[]
naIList<string>
je explicitní převod, nikoli implicitní. Přetypování(IList<string>)oa1
způsobí vyvolání výjimky za běhu, protožeoa1
odkazuje na aobject[]
nikoli nastring[]
. Přetypování (IList<string>)oa2
nezpůsobí výjimku, protožeoa2
odkazuje na .string[]
end example
Kdykoli existuje implicitní nebo explicitní převod odkazu na S[]
IList<T>
, existuje rovněž explicitní převod odkazu a IList<T>
jeho základní rozhraní (S[]
§10.3.5).
Při implementaci IList<T>
typu S[]
pole mohou některé členy implementovaného rozhraní vyvolat výjimky. Přesné chování implementace rozhraní je nad rámec této specifikace.
17.3 Vytvoření pole
Maticové instance jsou vytvořeny pomocí array_creation_expressions (§12.8.16.5) nebo deklaracemi polí nebo místních proměnných, které obsahují array_initializer (§17.7). Instance pole lze také vytvořit implicitně jako součást vyhodnocení seznamu argumentů zahrnujícího pole parametrů (§15.6.2.4).
Při vytvoření instance pole se vytvoří pořadí a délka každé dimenze a zůstane konstantní po celou dobu životnosti instance. Jinými slovy, pořadí existující instance pole není možné změnit ani změnit jeho rozměry.
Instance pole je vždy typu pole. Typ System.Array
je abstraktní typ, který nelze vytvořit instanci.
Prvky polí vytvořených array_creation_expressions jsou vždy inicializovány na výchozí hodnotu (§9.3).
Přístup k elementu Array 17.4
K prvkům pole se přistupuje pomocí výrazů element_access (§12.8.11.2) formuláře A[I₁, I₂, ..., Iₓ]
, kde A
je výraz typu pole a každý Iₑ
z nich je výraz typu int
, uint
, long
, ulong
nebo lze implicitně převést na jeden nebo více těchto typů. Výsledkem přístupu k prvku pole je proměnná, konkrétně prvek pole vybraný indexy.
Prvky pole lze vyčíslit pomocí foreach
příkazu (§13.9.5).
17.5 Maticové členy
Každý typ pole dědí členy deklarované typem System.Array
.
17.6 Kovariance matice
Pro všechny dva reference_type s a , pokud implicitní převod odkazu (§10.2.8) nebo explicitní převod odkazu (§10.3.5) existuje od A
B
tohoto typu do , pak stejný odkaz existuje také z typu A[R]
matice na typ B[R]
matice , kde R
je některý z daných rank_specifier (ale stejný pro oba typy matice).B
A
Tato relace se označuje jako kovariance pole. Maticová kovariance zejména znamená, že hodnota typu A[R]
pole může být ve skutečnosti odkazem na instanci typu B[R]
pole za předpokladu, že implicitní převod odkazu existuje z B
na A
.
Z důvodu kovariance matice zahrnují přiřazení prvků matice typu odkazu kontrolu za běhu, která zajišťuje, že hodnota přiřazená prvku pole je skutečně povoleného typu (§12.21.2).
Příklad:
class Test { static void Fill(object[] array, int index, int count, object value) { for (int i = index; i < index + count; i++) { array[i] = value; } } static void Main() { string[] strings = new string[100]; Fill(strings, 0, 100, "Undefined"); Fill(strings, 0, 10, null); Fill(strings, 90, 10, 0); } }
Přiřazení metody
array[i]
Fill
implicitně zahrnuje kontrolu za běhu, která zajišťuje, ževalue
jenull
odkaz nebo odkaz na objekt typu, který je kompatibilní se skutečným typemarray
prvku . VMain
, první dvě vyvoláníFill
úspěchu, ale třetí vyvolání způsobíSystem.ArrayTypeMismatchException
vyvolání při spuštění prvního přiřazení .array[i]
K výjimce dochází, protože poleint
nelze uložit dostring
pole.end example
Kovariance pole se konkrétně nevztahuje na pole value_types. Například neexistuje žádný převod, který umožňuje int[]
, aby bylo považováno object[]
za .
17.7 Inicializátory polí
Inicializátory polí mohou být zadány v prohlášeních polí (§15.5), deklarace místních proměnných (§13.6.2) a výrazy vytváření matice (§12.8.16.5):
array_initializer
: '{' variable_initializer_list? '}'
| '{' variable_initializer_list ',' '}'
;
variable_initializer_list
: variable_initializer (',' variable_initializer)*
;
variable_initializer
: expression
| array_initializer
;
Inicializátor pole se skládá z posloupnosti inicializátorů proměnných, uzavřených tokeny "{
" a "}
" a oddělené tokeny ",
". Každý inicializátor proměnné je výraz nebo v případě multidimenzionálního pole inicializátoru vnořeného pole.
Kontext, ve kterém se používá inicializátor pole, určuje typ inicializovaného pole. Ve výrazu vytvoření pole předchází typ pole bezprostředně před inicializátorem nebo je odvozen z výrazů v inicializátoru pole. V deklaraci pole nebo proměnné je typ pole nebo proměnné deklarován. Při použití inicializátoru pole nebo proměnné v deklaraci pole nebo proměnné
int[] a = {0, 2, 4, 6, 8};
je to jednoduše zkratka pro ekvivalentní výraz vytvoření pole:
int[] a = new int[] {0, 2, 4, 6, 8};
Pro jednorozměrnou matici se inicializátor pole skládá z posloupnosti výrazů, z nichž každý má implicitní převod na typ prvku matice (§10.2). Výrazy inicializují prvky pole ve vzestupné pořadí, počínaje elementem na nulu indexu. Počet výrazů v inicializátoru pole určuje délku vytvářené instance pole.
Příklad: Inicializátor pole výše vytvoří
int[]
instanci o délce 5 a pak inicializuje instanci s následujícími hodnotami:a[0] = 0; a[1] = 2; a[2] = 4; a[3] = 6; a[4] = 8;
end example
U multidimenzionálního pole musí inicializátor pole mít tolik úrovní vnoření, kolik má pole dimenzí. Vnější úroveň vnoření odpovídá levé dimenzi a nejvnitřnější úroveň vnoření odpovídá pravé dimenzi. Délka každé dimenze pole je určena počtem prvků na odpovídající úrovni vnoření v inicializátoru pole. Pro každý inicializátor vnořené pole musí být počet prvků stejný jako ostatní inicializátory pole na stejné úrovni.
Příklad: Příklad:
int[,] b = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
vytvoří dvojrozměrné pole s délkou pěti pro levou dimenzi a délkou dvou dimenzí úplně vpravo:
int[,] b = new int[5, 2];
a pak inicializuje instanci pole následujícími hodnotami:
b[0, 0] = 0; b[0, 1] = 1; b[1, 0] = 2; b[1, 1] = 3; b[2, 0] = 4; b[2, 1] = 5; b[3, 0] = 6; b[3, 1] = 7; b[4, 0] = 8; b[4, 1] = 9;
end example
Pokud je k dispozici jiná dimenze než nejvíce vpravo s délkou nula, předpokládá se, že následující dimenze mají také nulovou délku.
Příklad:
int[,] c = {};
vytvoří dvojrozměrné pole s délkou nuly pro levou i úplně pravou dimenzi:
int[,] c = new int[0, 0];
end example
Pokud výraz vytvoření pole obsahuje explicitní délky dimenzí i inicializátor pole, musí být délky konstantními výrazy a počet prvků na každé úrovni vnoření se shoduje s odpovídající délkou dimenze.
Příklad: Tady je několik příkladů:
int i = 3; int[] x = new int[3] {0, 1, 2}; // OK int[] y = new int[i] {0, 1, 2}; // Error, i not a constant int[] z = new int[3] {0, 1, 2, 3}; // Error, length/initializer mismatch
Inicializátor pro
y
výsledek chyby v době kompilace, protože výraz délky dimenze není konstanta a inicializátor proz
výsledky chyby v době kompilace, protože délka a počet prvků v inicializátoru nesouhlasí.end example
Poznámka: C# umožňuje koncovou čárku na konci array_initializer. Tato syntaxe poskytuje flexibilitu při přidávání nebo odstraňování členů z tohoto seznamu a zjednodušuje generování takových seznamů. koncová poznámka
ECMA C# draft specification