Dela via


17 matriser

17.1 Allmänt

En matris är en datastruktur som innehåller ett antal variabler som nås via beräknade index. Variablerna som finns i en matris, även kallade element i matrisen, är av samma typ och den här typen kallas elementtypen för matrisen.

En matris har en rangordning som avgör antalet index som är associerade med varje matriselement. Rangordningen för en matris kallas även matrisens dimensioner. En matris med rangordningen en kallas för en endimensionell matris. En matris med en rangordning som är större än en kallas för en flerdimensionell matris. Flerdimensionella matriser med specifik storlek kallas ofta för tvådimensionella matriser, tredimensionella matriser och så vidare. Varje dimension i en matris har en associerad längd som är ett heltal större än eller lika med noll. Dimensionslängderna är inte en del av matristypen, utan upprättas i stället när en instans av matristypen skapas vid körning. Längden på en dimension avgör det giltiga indexintervallet för den dimensionen: För en längddimension Nkan index variera från 0 till N – 1 inkluderande. Det totala antalet element i en matris är produkten av längden på varje dimension i matrisen. Om en eller flera av dimensionerna i en matris har en längd på noll, sägs matrisen vara tom.

Elementtypen för en matris kan i sig vara en matristyp (§17.2.1). Sådana matriser med matriser skiljer sig från flerdimensionella matriser och kan användas för att representera "ojämna matriser".

Exempel:

int[][] pascals = 
{
    new int[] {1},
    new int[] {1, 1},
    new int[] {1, 2, 1},
    new int[] {1, 3, 3, 1}
};

slutexempel

Varje matristyp är en referenstyp (§8.2). Elementtypen för en matris kan vara vilken typ som helst, inklusive värdetyper och matristyper.

17.2 Matristyper

17.2.1 Allmänt

Grammatikproduktionerna för matristyper finns i §8.2.1.

En matristyp skrivs som en non_array_type följt av en eller flera rank_specifiers.

En non_array_type är en typ som inte i sig är en array_type.

Rangordningen för en matristyp anges av den vänstra rank_specifier i array_type: En rank_specifier anger att matrisen är en matris med en rangordning på en plus antalet "," token i rank_specifier.

Elementtypen för en matristyp är den typ som är resultatet av att ta bort den vänstra rank_specifier:

  • En matristyp i formuläret T[R] är en matris med rangordning R och en elementtyp som Tinte är matris .
  • En matristyp i formuläret T[R][R₁]...[Rₓ] är en matris med rangordning R och en elementtyp T[R₁]...[Rₓ].

I själva verket läss rank_specifier s från vänster till höger före den sista elementtypen som inte är matris.

Exempel: Typen i T[][,,][,] är en endimensionell matris med tredimensionella matriser med tvådimensionella matriser av int. slutexempel

Vid körning kan ett värde av en matristyp vara null eller en referens till en instans av den matristypen.

Obs! Enligt reglerna i §17.6 kan värdet också vara en referens till en covariant matristyp. slutkommentar

17.2.2 Typen System.Array

Typen System.Array är den abstrakta bastypen för alla matristyper. En implicit referenskonvertering (§10.2.8) finns från valfri matristyp till System.Array och till alla gränssnittstyper som implementeras av System.Array. En explicit referenskonvertering (§10.3.5) finns från System.Array och alla gränssnittstyper som implementeras av System.Array till valfri matristyp. System.Array är inte i sig en array_type. I stället är det en class_type som alla array_types härleds från.

Vid körning kan ett värde av typen System.Array vara null eller en referens till en instans av valfri matristyp.

17.2.3 Matriser och allmänna samlingsgränssnitt

En endimensionell matris T[] implementerar gränssnittet System.Collections.Generic.IList<T> (IList<T> för kort) och dess basgränssnitt. Det finns därför en implicit konvertering från T[] till IList<T> och dess basgränssnitt. Dessutom, om det finns en implicit referenskonvertering från S till implementerar IList<T> S[] och det finns en implicit referenskonvertering från S[] till IList<T> och dess basgränssnitt (§10.2.8T). Om det finns en explicit referenskonvertering från S till T finns det en explicit referenskonvertering från S[] till IList<T> och dess basgränssnitt (§10.3.5).

På samma sätt implementerar en endimensionell matris T[] även gränssnittet System.Collections.Generic.IReadOnlyList<T> (IReadOnlyList<T> för kort) och dess basgränssnitt. Det finns därför en implicit konvertering från T[] till IReadOnlyList<T> och dess basgränssnitt. Dessutom, om det finns en implicit referenskonvertering från S till implementerar IReadOnlyList<T> S[] och det finns en implicit referenskonvertering från S[] till IReadOnlyList<T> och dess basgränssnitt (§10.2.8T). Om det finns en explicit referenskonvertering från S till T finns det en explicit referenskonvertering från S[] till IReadOnlyList<T> och dess basgränssnitt (§10.3.5).

Exempel: Till exempel:

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
    }
}

lst2 = oa1 Tilldelningen genererar ett kompileringsfel eftersom konverteringen från object[] till IList<string> är en explicit konvertering, inte implicit. Gjutningen (IList<string>)oa1 gör att ett undantag genereras vid körning eftersom oa1 refererar till en object[] och inte en string[]. Casten (IList<string>)oa2 orsakar dock inte att ett undantag utlöses eftersom oa2 refererar till en string[].

slutexempel

När det finns en implicit eller explicit referenskonvertering från S[] till IList<T>finns det också en explicit referenskonvertering från IList<T> och dess basgränssnitt till S[] (§10.3.5).

När en matristyp S[] implementerar IList<T>kan vissa medlemmar i det implementerade gränssnittet utlösa undantag. Det exakta beteendet för implementeringen av gränssnittet ligger utanför den här specifikationens omfång.

17.3 Matrisskapande

Matrisinstanser skapas av array_creation_expression(§12.8.16.5) eller av fält- eller lokala variabeldeklarationer som innehåller en array_initializer (§17.7). Matrisinstanser kan också skapas implicit som en del av utvärderingen av en argumentlista med en parametermatris (§15.6.2.4).

När en matrisinstans skapas upprättas rangordningen och längden på varje dimension och förblir sedan konstant under hela instansens livslängd. Med andra ord går det inte att ändra rangordningen för en befintlig matrisinstans och det går inte heller att ändra storlek på dess dimensioner.

En matrisinstans är alltid av en matristyp. Typen System.Array är en abstrakt typ som inte kan instansieras.

Element i matriser som skapats av array_creation_expressions initieras alltid till deras standardvärde (§9.3).

17.4 Matriselementåtkomst

Matriselement används med hjälp av element_access uttryck (§12.8.11.2) i formuläret A[I₁, I₂, ..., Iₓ], där A är ett uttryck av en matristyp och var Iₑ och en är ett uttryck av typen int, , uintlong, ulongeller kan implicit konverteras till en eller flera av dessa typer. Resultatet av en matriselementåtkomst är en variabel, nämligen matriselementet som väljs av indexen.

Elementen i en matris kan räknas upp med hjälp av en foreach instruktion (§13.9.5).

17,5 matrismedlemmar

Varje matristyp ärver de medlemmar som deklareras av System.Array typen .

17.6 Matriskovarians

För två reference_type s och , om det finns en implicit referenskonvertering (§10.2.8) eller explicit referenskonvertering (§10.3.5) från A till B, så finns samma referenskonvertering också från matristypen A[R] till matristypen B[R], där R finns en viss rank_specifier (men samma för båda matristyperna).BA Den här relationen kallas matriskovarians. I synnerhet matriskovarians innebär att ett värde av en matristyp A[R] faktiskt kan vara en referens till en instans av en matristyp B[R], förutsatt att det finns en implicit referenskonvertering från B till A.

På grund av matriskovarians omfattar tilldelningar till element av referenstypmatriser en körningskontroll som säkerställer att värdet som tilldelas till matriselementet faktiskt är av en tillåten typ (§12.21.2).

Exempel:

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);
    }
}

Tilldelningen till array[i] i metoden innehåller implicit en körningskontroll, som säkerställer att det value antingen är en null referens eller en referens till ett objekt av en typ som är kompatibelt med den faktiska elementtypen array.Fill I Mainlyckas de två första anropen Fill , men det tredje anropet gör att en System.ArrayTypeMismatchException utlöses när den första tilldelningen körs till array[i]. Undantaget beror på att en ruta int inte kan lagras i en string matris.

slutexempel

Matriskovarians utökar inte specifikt till matriser med value_types. Det finns till exempel ingen konvertering som tillåter att en int[] behandlas som en object[].

17.7 Matrisinitierare

Matrisinitierare kan anges i fältdeklarationer (§15.5), lokala variabeldeklarationer (§13.6.2) och matrisskapandeuttryck (§12.8.16.5):

array_initializer
    : '{' variable_initializer_list? '}'
    | '{' variable_initializer_list ',' '}'
    ;

variable_initializer_list
    : variable_initializer (',' variable_initializer)*
    ;
    
variable_initializer
    : expression
    | array_initializer
    ;

En matrisinitierare består av en sekvens med variabelinitierare som omges av "{" och "}" token och avgränsas med "," token. Varje variabelinitierare är ett uttryck eller, om det gäller en flerdimensionell matris, en kapslad matrisinitierare.

Kontexten där en matrisinitierare används avgör vilken typ av matris som initieras. I ett uttryck för att skapa matriser föregår matristypen omedelbart initieraren, eller härleds från uttrycken i matrisinitieraren. I en fält- eller variabeldeklaration är matristypen typen av fält eller variabel som deklareras. När en matrisinitierare används i ett fält eller en variabeldeklaration,

int[] a = {0, 2, 4, 6, 8};

det är bara en förkortning för ett motsvarande uttryck för skapande av matriser:

int[] a = new int[] {0, 2, 4, 6, 8};

För en endimensionell matris ska matrisinitieraren bestå av en sekvens med uttryck som var och en har en implicit konvertering till matrisens elementtyp (§10.2). Uttrycken initierar matriselement i ökande ordning, med början med elementet vid index noll. Antalet uttryck i matrisinitieraren avgör längden på matrisinstansen som skapas.

Exempel: Matrisinitieraren ovan skapar en int[] instans av längd 5 och initierar sedan instansen med följande värden:

a[0] = 0; a[1] = 2; a[2] = 4; a[3] = 6; a[4] = 8;

slutexempel

För en flerdimensionell matris ska matrisinitieraren ha lika många kapslingsnivåer som det finns dimensioner i matrisen. Den yttersta kapslingsnivån motsvarar den vänstra dimensionen och den innersta kapslingsnivån motsvarar den högra dimensionen. Längden på varje dimension i matrisen bestäms av antalet element på motsvarande kapslingsnivå i matrisinitieraren. För varje kapslad matrisinitierare ska antalet element vara samma som de andra matrisinitierarna på samma nivå.

Exempel: Exemplet:

int[,] b = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};

skapar en tvådimensionell matris med en längd på fem för den vänstra dimensionen och en längd på två för den högra dimensionen:

int[,] b = new int[5, 2];

och initierar sedan matrisinstansen med följande värden:

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;

slutexempel

Om en annan dimension än den högra anges med längd noll antas de efterföljande dimensionerna också ha längd noll.

Exempel:

int[,] c = {};

skapar en tvådimensionell matris med en längd på noll för både den vänstra och den högra dimensionen:

int[,] c = new int[0, 0];

slutexempel

När ett uttryck för skapande av matris innehåller både explicita dimensionslängder och en matrisinitierare ska längderna vara konstanta uttryck och antalet element på varje kapslingsnivå ska matcha motsvarande dimensionslängd.

Exempel: Här är några exempel:

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

Här resulterar initiatorn för y ett kompileringsfel eftersom dimensionslängdsuttrycket inte är en konstant, och initiatorn för z resulterar i ett kompileringsfel eftersom längden och antalet element i initieraren inte stämmer överens.

slutexempel

Obs! C# tillåter ett avslutande kommatecken i slutet av en array_initializer. Den här syntaxen ger flexibilitet när det gäller att lägga till eller ta bort medlemmar från en sådan lista och förenklar datorgenereringen av sådana listor. slutkommentar