17 matrices
17.1 Algemeen
Een matrix is een gegevensstructuur die een aantal variabelen bevat die toegankelijk zijn via berekende indexen. De variabelen in een matrix, ook wel de elementen van de matrix genoemd, zijn allemaal van hetzelfde type en dit type wordt het elementtype van de matrix genoemd.
Een matrix heeft een rang die het aantal indexen bepaalt dat aan elk matrixelement is gekoppeld. De rang van een matrix wordt ook wel de dimensies van de matrix genoemd. Een matrix met een rang van één wordt een eendimensionale matrix genoemd. Een matrix met een rang groter dan één wordt een multidimensionale matrix genoemd. Multidimensionale matrices met een specifieke grootte worden vaak tweedimensionale matrices, driedimensionale matrices enzovoort genoemd. Elke dimensie van een matrix heeft een bijbehorende lengte die een integraal getal is dat groter is dan of gelijk is aan nul. De dimensielengten maken geen deel uit van het type matrix, maar worden eerder vastgesteld wanneer een exemplaar van het matrixtype wordt gemaakt tijdens runtime. De lengte van een dimensie bepaalt het geldige bereik van indexen voor die dimensie: Voor een dimensie van lengte N
kunnen indexen variëren van 0
tot N – 1
inclusief. Het totale aantal elementen in een matrix is het product van de lengten van elke dimensie in de matrix. Als een of meer dimensies van een matrix een lengte van nul hebben, wordt gezegd dat de matrix leeg is.
Het elementtype van een matrix kan zelf een matrixtype zijn (§17.2.1). Dergelijke matrices van matrices verschillen van multidimensionale matrices en kunnen worden gebruikt om 'onregelmatige matrices' weer te geven.
Voorbeeld:
int[][] pascals = { new int[] {1}, new int[] {1, 1}, new int[] {1, 2, 1}, new int[] {1, 3, 3, 1} };
eindvoorbeeld
Elk matrixtype is een referentietype (§8.2). Het elementtype van een matrix kan elk type zijn, inclusief waardetypen en matrixtypen.
17.2 Matrixtypen
17.2.1 Algemeen
De grammaticaproducties voor matrixtypen worden verstrekt in §8.2.1.
Een matrixtype wordt geschreven als een non_array_type gevolgd door een of meer rank_specifiers.
Een non_array_type is een type dat geen array_type is.
De rang van een matrixtype wordt gegeven door de meest linkse rank_specifier in de array_type: Een rank_specifier geeft aan dat de matrix een matrix is met een rang van één plus het aantal tokens,
in de rank_specifier.
Het elementtype van een matrixtype is het type dat het resultaat is van het verwijderen van de meest linkse rank_specifier:
- Een matrixtype van het formulier
T[R]
is een matrix met rang enR
een niet-matrixelementtypeT
. - Een matrixtype van het formulier
T[R][R₁]...[Rₓ]
is een matrix met rangR
en een elementtypeT[R₁]...[Rₓ]
.
In feite worden de rank_specifiers gelezen van links naar rechts voor het uiteindelijke elementtype dat niet van de matrix is.
Voorbeeld: Het type is
T[][,,][,]
een eendimensionale matrix van driedimensionale matrices van tweedimensionale matrices vanint
. eindvoorbeeld
Tijdens runtime kan een waarde van een matrixtype of een verwijzing naar een exemplaar van dat matrixtype zijn null
.
Opmerking: Volgens de regels van §17.6 kan de waarde ook verwijzen naar een covariant matrixtype. eindnotitie
17.2.2 Het type System.Array
Het type System.Array
is het abstracte basistype van alle matrixtypen. Er bestaat een impliciete verwijzingsconversie (§10.2.8) van elk matrixtype naar System.Array
en naar elk interfacetype dat wordt geïmplementeerd door System.Array
. Er bestaat een expliciete verwijzingsconversie (§10.3.5) van System.Array
en elk interfacetype dat door System.Array
elk matrixtype wordt geïmplementeerd. System.Array
is zelf geen array_type. In plaats daarvan is het een class_type waaruit alle array_types zijn afgeleid.
Tijdens runtime kan een waarde van het type System.Array
of een verwijzing naar een exemplaar van elk matrixtype zijn null
.
17.2.3 Matrices en de algemene verzamelingsinterfaces
Een enkeledimensionale matrix T[]
implementeert de interface System.Collections.Generic.IList<T>
(IList<T>
kortom) en de basisinterfaces. Daarom is er een impliciete conversie van T[]
naar IList<T>
en de basisinterfaces. Bovendien, als er een impliciete verwijzingsconversie van S
naar T
vervolgens S[]
wordt geïmplementeerd IList<T>
en er een impliciete verwijzingsconversie van S[]
naar IList<T>
en de basisinterfaces (§10.2.8) is. Als er een expliciete verwijzingsconversie van S
naar T
is, is er een expliciete verwijzingsconversie van S[]
naar IList<T>
en de basisinterfaces (§10.3.5).
Op dezelfde manier implementeert een enkeledimensionale matrix T[]
ook de interface System.Collections.Generic.IReadOnlyList<T>
(IReadOnlyList<T>
kortom) en de basisinterfaces. Daarom is er een impliciete conversie van T[]
naar IReadOnlyList<T>
en de basisinterfaces. Bovendien, als er een impliciete verwijzingsconversie van S
naar T
vervolgens S[]
wordt geïmplementeerd IReadOnlyList<T>
en er een impliciete verwijzingsconversie van S[]
naar IReadOnlyList<T>
en de basisinterfaces (§10.2.8) is. Als er een expliciete verwijzingsconversie van S
naar T
is, is er een expliciete verwijzingsconversie van S[]
naar IReadOnlyList<T>
en de basisinterfaces (§10.3.5).
Voorbeeld: bijvoorbeeld:
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 } }
De toewijzing
lst2 = oa1
genereert een compilatiefout omdat de conversie vanobject[]
naarIList<string>
een expliciete conversie, niet impliciet, is. De cast(IList<string>)oa1
zorgt ervoor dat er tijdens runtime een uitzondering wordt gegenereerd omdatoa1
er wordt verwezen naar eenobject[]
en niet eenstring[]
. De cast (IList<string>)oa2
veroorzaakt echter geen uitzondering omdat er wordt verwezen naaroa2
eenstring[]
.eindvoorbeeld
Wanneer er een impliciete of expliciete verwijzingsconversie van S[]
naar IList<T>
is, is er ook een expliciete verwijzingsconversie van IList<T>
en de basisinterfaces naar S[]
(§10.3.5).
Wanneer een matrixtype S[]
wordt geïmplementeerd IList<T>
, kunnen sommige leden van de geïmplementeerde interface uitzonderingen genereren. Het precieze gedrag van de implementatie van de interface valt buiten het bereik van deze specificatie.
17.3 Matrix maken
Matrixinstanties worden gemaakt door array_creation_expression s (§12.8.16.5) of door veld- of lokale variabeledeclaraties die een array_initializer bevatten (§17.7). Matrixexemplaren kunnen ook impliciet worden gemaakt als onderdeel van het evalueren van een argumentenlijst met een parametermatrix (§15.6.2.4).
Wanneer er een matrixexemplaren worden gemaakt, worden de rang en lengte van elke dimensie tot stand gebracht en blijven deze vervolgens constant gedurende de gehele levensduur van het exemplaar. Met andere woorden, het is niet mogelijk om de rang van een bestaand matrixexemplaren te wijzigen, en het is ook niet mogelijk om de afmetingen ervan te wijzigen.
Een matrixinstantie is altijd van een matrixtype. Het System.Array
type is een abstract type dat niet kan worden geïnstantieerd.
Elementen van matrices die door array_creation_expression szijn gemaakt, worden altijd geïnitialiseerd naar hun standaardwaarde (§9.3).
17.4 Toegang tot matrixelementen
Matrixelementen worden geopend met behulp van element_access expressies (§12.8.11.2) van het formulier A[I₁, I₂, ..., Iₓ]
, waarbij A
een expressie van een matrixtype is en elk Iₑ
een expressie van het type int
, uint
, long
of ulong
kan impliciet worden geconverteerd naar een of meer van deze typen. Het resultaat van toegang tot een matrixelement is een variabele, namelijk het matrixelement dat door de indexen is geselecteerd.
De elementen van een matrix kunnen worden geïnventariseerd met behulp van een foreach
instructie (§13.9.5).
17.5 Matrixleden
Elk matrixtype neemt de leden over die door het System.Array
type zijn gedeclareerd.
17.6 Covariantie van matrix
Voor twee reference_type s en, als er een impliciete verwijzingsconversie (§10.2.8) of expliciete verwijzingsconversie (§10.3.5) bestaat, B
A
bestaat dezelfde verwijzingsconversie ook van het matrixtype naar het matrixtypeB[R]
A[R]
, waarbij R
een gegeven rank_specifier (maar hetzelfde voor beide matrixtypen).B
A
Deze relatie staat bekend als matrixcovariantie. Matrixcovariantie betekent met name dat een waarde van een matrixtype A[R]
in feite een verwijzing kan zijn naar een exemplaar van een matrixtype B[R]
, mits er een impliciete verwijzingsconversie bestaat van B
naar A
.
Vanwege de covariantie van de matrix bevatten toewijzingen aan elementen van referentietypematrices een runtimecontrole die ervoor zorgt dat de waarde die aan het matrixelement wordt toegewezen, daadwerkelijk van een toegestaan type is (§12.21.2).
Voorbeeld:
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); } }
De toewijzing aan
array[i]
in deFill
methode omvat impliciet een runtimecontrole, die ervoor zorgt datvalue
dit eennull
verwijzing is of een verwijzing naar een object van een type dat compatibel is met het werkelijke elementtype vanarray
. InMain
, de eerste twee aanroepen van slagen, maar de derde aanroep zorgt ervoor dat er eenSystem.ArrayTypeMismatchException
wordt gegenereerd bij het uitvoeren vanFill
de eerste opdracht aanarray[i]
. De uitzondering treedt op omdat een vakint
niet kan worden opgeslagen in eenstring
matrix.eindvoorbeeld
De covariantie van de matrix wordt specifiek niet uitgebreid naar matrices van value_types. Er bestaat bijvoorbeeld geen conversie waarmee een int[]
kan worden behandeld als een object[]
.
17.7 Initializers van matrices
Matrix initialisaties kunnen worden opgegeven in velddeclaraties (§15.5), declaraties van lokale variabelen (§13.6.2) en expressies voor het maken van matrices (§12.8.16.5):
array_initializer
: '{' variable_initializer_list? '}'
| '{' variable_initializer_list ',' '}'
;
variable_initializer_list
: variable_initializer (',' variable_initializer)*
;
variable_initializer
: expression
| array_initializer
;
Een matrix-initialisatiefunctie bestaat uit een reeks variabele initialisaties, tussen tokens '{
' en '}
' en gescheiden door ',
'-tokens. Elke variabele initialisatiefunctie is een expressie of, in het geval van een multidimensionale matrix, een geneste initialisatiefunctie voor matrices.
De context waarin een matrix-initialisatiefunctie wordt gebruikt, bepaalt het type van de matrix die wordt geïnitialiseerd. In een expressie voor het maken van een matrix wordt het matrixtype direct voorafgegaan door de initialisatiefunctie of wordt afgeleid van de expressies in de initialisatiefunctie van de matrix. In een veld- of variabeledeclaratie is het matrixtype het type van het veld of de variabele die wordt gedeclareerd. Wanneer een matrix-initialisatiefunctie wordt gebruikt in een veld- of variabeledeclaratie,
int[] a = {0, 2, 4, 6, 8};
het is gewoon een afkorting voor een equivalente expressie voor het maken van een matrix:
int[] a = new int[] {0, 2, 4, 6, 8};
Voor een eendimensionale matrix bestaat de initialisatiefunctie van de matrix uit een reeks expressies, elk met een impliciete conversie naar het elementtype van de matrix (§10.2). De expressies initialiseren matrixelementen in oplopende volgorde, beginnend met het element bij index nul. Het aantal expressies in de matrix-initialisatiefunctie bepaalt de lengte van het matrixexemplaren dat wordt gemaakt.
Voorbeeld: Met de bovenstaande matrix initialisatie wordt een
int[]
exemplaar van lengte 5 gemaakt en wordt het exemplaar vervolgens geïnitialiseerd met de volgende waarden:a[0] = 0; a[1] = 2; a[2] = 4; a[3] = 6; a[4] = 8;
eindvoorbeeld
Voor een multidimensionale matrix moet de initialisatiefunctie van de matrix zoveel nestniveaus hebben als er dimensies in de matrix zijn. Het buitenste nestniveau komt overeen met de meest linkse dimensie en het binnenste nestniveau komt overeen met de meest rechtse dimensie. De lengte van elke dimensie van de matrix wordt bepaald door het aantal elementen op het bijbehorende nestniveau in de initialisatiefunctie van de matrix. Voor elke geneste matrix-initialisatiefunctie moet het aantal elementen hetzelfde zijn als de andere matrix-initializers op hetzelfde niveau.
Voorbeeld: Het voorbeeld:
int[,] b = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
maakt een tweedimensionale matrix met een lengte van vijf voor de meest linkse dimensie en een lengte van twee voor de meest rechtse dimensie:
int[,] b = new int[5, 2];
en initialiseert het matrixexemplaren met de volgende waarden:
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;
eindvoorbeeld
Als een andere dimensie dan de meest rechtse wordt opgegeven met lengte nul, wordt ervan uitgegaan dat de volgende dimensies ook lengte nul hebben.
Voorbeeld:
int[,] c = {};
maakt een tweedimensionale matrix met een lengte van nul voor zowel de meest linkse als de meest rechtse dimensie:
int[,] c = new int[0, 0];
eindvoorbeeld
Wanneer een expressie voor het maken van een matrix zowel expliciete dimensielengten als een matrix-initialisatiefunctie bevat, moeten de lengten constante expressies zijn en moet het aantal elementen op elk nestniveau overeenkomen met de bijbehorende dimensielengte.
Voorbeeld: Hier volgen enkele voorbeelden:
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
Hier is de initialisatiefunctie voor
y
resultaten in een compilatietijdfout omdat de dimensielengte-expressie geen constante is en de initialisatiefunctie voorz
een compilatiefout omdat de lengte en het aantal elementen in de initialisatiefunctie niet overeenkomen.eindvoorbeeld
Opmerking: C# staat een volgkomma toe aan het einde van een array_initializer. Deze syntaxis biedt flexibiliteit bij het toevoegen of verwijderen van leden uit een dergelijke lijst en vereenvoudigt het genereren van dergelijke lijsten. eindnotitie
ECMA C# draft specification