Freigeben über


17 Arrays

17.1 Allgemein

Ein Array ist eine Datenstruktur, die eine Anzahl von Variablen enthält, auf die über berechnete Indizes zugegriffen wird. Die im Array enthaltenen Variablen, auch Elemente des Arrays genannt, weisen alle denselben Typ auf. Dieser Typ wird als Elementtyp des Arrays bezeichnet.

Ein Array verfügt über einen Rang, der die Anzahl der Indizes bestimmt, die jedem Arrayelement zugeordnet sind. Der Rang eines Arrays wird auch als Dimensionen des Arrays bezeichnet. Ein Array mit einer Rangfolge wird als eindimensionales Array bezeichnet. Ein Array mit einem Rang größer als einer wird als mehrdimensionales Array bezeichnet. Spezifische mehrdimensionale Arrays werden häufig als zweidimensionale Arrays, dreidimensionale Arrays usw. bezeichnet. Jede Dimension eines Arrays weist eine zugeordnete Länge auf, die eine integrale Zahl größer oder gleich Null ist. Die Dimensionslängen sind nicht Teil des Arraytyps, sondern werden eingerichtet, wenn zur Laufzeit eine Instanz des Arraytyps erstellt wird. Die Länge einer Dimension bestimmt den gültigen Indizesbereich für diese Dimension: Für eine Dimension der Länge Nkönnen Indizes von 0 einschließlich reichen N – 1 . Die Gesamtanzahl der Elemente in einem Array ist das Produkt der Längen jeder Dimension im Array. Wenn eine oder mehrere Dimensionen eines Arrays eine Länge von Null aufweisen, wird das Array als leer angegeben.

Der Elementtyp eines Arrays kann selbst ein Arraytyp sein (§17.2.1). Solche Arrays von Arrays unterscheiden sich von mehrdimensionalen Arrays und können verwendet werden, um "gezackte Arrays" darzustellen.

Beispiel:

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

Endbeispiel

Jeder Arraytyp ist ein Bezugstyp (§8.2). Der Elementtyp eines Arrays kann ein beliebiger Typ sein, einschließlich Werttypen und Arraytypen.

17.2 Arraytypen

17.2.1 Allgemein

Die Grammatikproduktionen für Arraytypen werden in §8.2.1 bereitgestellt.

Ein Arraytyp wird als non_array_type gefolgt von mindestens einem rank_specifiergeschrieben.

Ein non_array_type ist jeder Typ , der nicht selbst ein array_type ist.

Der Rang eines Arraytyps wird von der äußerst linken rank_specifier im array_type angegeben: Ein rank_specifier gibt an, dass es sich bei dem Array um ein Array mit einer Rangfolge und der Anzahl der ","-Token im rank_specifier handelt.

Der Elementtyp eines Arraytyps ist der Typ, der aus dem Löschen der äußersten linken rank_specifier resultiert:

  • Ein Arraytyp des Formulars T[R] ist ein Array mit Rang R und einem Nicht-Array-Elementtyp T.
  • Ein Arraytyp des Formulars T[R][R₁]...[Rₓ] ist ein Array mit Rang R und Elementtyp T[R₁]...[Rₓ].

Tatsächlich werden die rank_specifiervon links nach rechts vor dem endgültigen Nicht-Array-Elementtyp gelesen.

Beispiel: Der Typ in T[][,,][,] ist ein eindimensionales Array von dreidimensionalen Arrays von zweidimensionalen Arrays von int. Endbeispiel

Zur Laufzeit kann ein Wert eines Arraytyps oder ein Verweis auf eine Instanz dieses Arraytyps sein null .

Hinweis: Nach den Regeln von §17.6 kann der Wert auch ein Verweis auf einen kovarianten Arraytyp sein. Endnote

17.2.2 Der System.Array-Typ

Der Typ System.Array ist der abstrakte Basistyp aller Arraytypen. Eine implizite Verweiskonvertierung (§10.2.8) ist von jedem Arraytyp zu System.Array und zu jedem von ihnen implementierten Schnittstellentyp vorhanden System.Array. Es ist eine explizite Verweiskonvertierung (§10.3.5) vorhanden System.Array und alle Schnittstellentypen, die von System.Array einem beliebigen Arraytyp implementiert werden. System.Array ist nicht selbst ein array_type. Vielmehr handelt es sich um eine class_type , von der alle array_typeabgeleitet werden.

Zur Laufzeit kann ein Wert des Typs System.Array oder ein Verweis auf eine Instanz eines beliebigen Arraytyps sein null .

17.2.3 Arrays und die generischen Sammlungsschnittstellen

Ein eindimensionales Array T[] implementiert die Schnittstelle System.Collections.Generic.IList<T> (IList<T> kurz) und die zugehörigen Basisschnittstellen. Dementsprechend gibt es eine implizite Konvertierung von T[] zu IList<T> und deren Basisschnittstellen. Darüber hinaus wird eine implizite Verweiskonvertierung von S zu T deren S[] Implementierung implementiert, und es gibt eine implizite Verweiskonvertierung von S[] und IList<T> deren Basisschnittstellen (§10.2.8).IList<T> Wenn es eine explizite Verweiskonvertierung von S in T die gibt, gibt es eine explizite Verweiskonvertierung von S[] zu IList<T> und deren Basisschnittstellen (§10.3.5).

Ebenso implementiert ein eindimensionales Array T[] auch die Schnittstelle System.Collections.Generic.IReadOnlyList<T> (IReadOnlyList<T> kurz) und ihre Basisschnittstellen. Dementsprechend gibt es eine implizite Konvertierung von T[] zu IReadOnlyList<T> und deren Basisschnittstellen. Darüber hinaus wird eine implizite Verweiskonvertierung von S zu T deren S[] Implementierung implementiert, und es gibt eine implizite Verweiskonvertierung von S[] und IReadOnlyList<T> deren Basisschnittstellen (§10.2.8).IReadOnlyList<T> Wenn es eine explizite Verweiskonvertierung von S in T die gibt, gibt es eine explizite Verweiskonvertierung von S[] zu IReadOnlyList<T> und deren Basisschnittstellen (§10.3.5).

Beispiel:

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

Die Zuordnung lst2 = oa1 generiert einen Kompilierungsfehler, da die Konvertierung von object[] zu IList<string> einer expliziten Konvertierung und nicht implizit ist. Die Umwandlung (IList<string>)oa1 führt dazu, dass eine Ausnahme zur Laufzeit ausgelöst wird, da oa1 verweise auf ein object[] und nicht ein string[]. Die Umwandlung (IList<string>)oa2 führt jedoch nicht dazu, dass eine Ausnahme ausgelöst wird, da oa2 verweise auf eine string[].

Endbeispiel

Wenn es eine implizite oder explizite Referenzkonvertierung von S[] zu IList<T>, gibt es auch eine explizite Verweiskonvertierung von IList<T> und deren Basisschnittstellen in S[] (§10.3.5).

Wenn ein Arraytyp S[] implementiert wird IList<T>, können einige Der Member der implementierten Schnittstelle Ausnahmen auslösen. Das genaue Verhalten der Implementierung der Schnittstelle liegt außerhalb des Umfangs dieser Spezifikation.

17.3 Arrayerstellung

Arrayinstanzen werden von array_creation_expression s (§12.8.16.5) oder von Feld- oder lokalen Variablendeklarationen erstellt, die eine array_initializer (§17.7) enthalten. Arrayinstanzen können auch implizit als Teil der Auswertung einer Argumentliste mit einem Parameterarray (§15.6.2.4) erstellt werden.

Wenn eine Arrayinstanz erstellt wird, werden der Rang und die Länge jeder Dimension eingerichtet und bleiben dann für die gesamte Lebensdauer der Instanz konstant. Mit anderen Worten, es ist nicht möglich, den Rang einer vorhandenen Arrayinstanz zu ändern, noch ist es möglich, die Größe seiner Dimensionen zu ändern.

Eine Arrayinstanz weist immer einen Arraytyp auf. Der System.Array Typ ist ein abstrakter Typ, der nicht instanziiert werden kann.

Elemente von Arrays, die von array_creation_expressions erstellt werden, werden immer mit ihrem Standardwert initialisiert (§9.3).

17.4 Arrayelementzugriff

Auf Arrayelemente wird mithilfe von element_access Ausdrücken (§12.8.11.2) des Formulars A[I₁, I₂, ..., Iₓ]zugegriffen, wobei A es sich um einen Ausdruck eines Arraytyps handelt, wobei es sich um Iₑ einen Ausdruck vom Typ int, , uint, long, ulongoder die implizite Konvertierung in einen oder mehrere dieser Typen handelt. Das Ergebnis eines Arrayelementzugriffs ist eine Variable, nämlich das Arrayelement, das von den Indizes ausgewählt wurde.

Die Elemente eines Arrays können mithilfe einer foreach Anweisung (§13.9.5) aufgezählt werden.

17.5 Arraymitglieder

Jeder Arraytyp erbt die vom System.Array Typ deklarierten Member.

17.6 Arraykovarianz

Bei zwei reference_type Aund B, wenn eine implizite Verweiskonvertierung (§10.2.8) oder explizite Verweiskonvertierung (§10.3.5) von A in B, ist die gleiche Verweiskonvertierung auch von dem Arraytyp in den Arraytyp B[R]A[R] vorhanden, wobei R ein beliebiger rank_specifier (aber für beide Arraytypen identisch) ist. Diese Beziehung wird als Arraykovarianz bezeichnet. Die Arraykovarianz bedeutet insbesondere, dass ein Wert eines Arraytyps A[R] tatsächlich ein Verweis auf eine Instanz eines Arraytyps B[R]sein kann, vorausgesetzt, eine implizite Verweiskonvertierung ist von B zu A.

Aufgrund der Arraykovarianz enthalten Zuordnungen zu Elementen des Referenztyparrays eine Laufzeitüberprüfung, mit der sichergestellt wird, dass der dem Arrayelement zugewiesene Wert tatsächlich einen zulässigen Typ aufweist (§12.21.2).

Beispiel:

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

Die Zuordnung array[i] in der Fill Methode enthält implizit eine Laufzeitüberprüfung, die sicherstellt, dass es value sich um einen null Verweis oder einen Verweis auf ein Objekt eines Typs handelt, der mit dem tatsächlichen Elementtyp arraykompatibel ist. In Main, die ersten beiden Aufrufe erfolgreich Fill , aber der dritte Aufruf bewirkt, dass eine System.ArrayTypeMismatchException ausgelöst wird, wenn die erste Zuordnung ausgeführt array[i]wird. Die Ausnahme tritt auf, da ein Boxed int nicht in einem string Array gespeichert werden kann.

Endbeispiel

Arraykovarianz erstreckt sich speziell nicht auf Arrays von value_types. Beispielsweise ist keine Konvertierung vorhanden, die eine int[] Behandlung als eine object[].

17.7 Arrayinitialisierer

Arrayinitialisierer können in Felddeklarationen (§15.5), lokalen Variablendeklarationen (§13.6.2) und Arrayerstellungsausdrücken (§12.8.16.5) angegeben werden:

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

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

Ein Arrayinitialisierer besteht aus einer Sequenz variabler Initialisierer, eingeschlossen durch "{" und "}" Token und durch "" Token getrennt durch ","-Token. Jeder Variableninitialisierer ist ein Ausdruck oder im Fall eines mehrdimensionalen Arrays ein geschachtelter Arrayinitialisierer.

Der Kontext, in dem ein Arrayinitialisierer verwendet wird, bestimmt den Typ des Arrays, das initialisiert wird. In einem Arrayerstellungsausdruck steht der Arraytyp unmittelbar vor dem Initialisierer oder wird von den Ausdrücken im Arrayinitialisierer abgeleitet. In einer Feld- oder Variablendeklaration ist der Arraytyp der Typ des deklarierten Felds oder der Variablen. Wenn ein Arrayinitialisierer in einer Feld- oder Variablendeklaration verwendet wird,

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

es ist einfach kurz für einen entsprechenden Arrayerstellungsausdruck:

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

Bei einem eindimensionalen Array muss der Arrayinitialisierer aus einer Abfolge von Ausdrücken bestehen, die jeweils eine implizite Konvertierung in den Elementtyp des Arrays haben (§10.2). Die Ausdrücke initialisieren Arrayelemente in zunehmender Reihenfolge, beginnend mit dem Element bei Index 0. Die Anzahl der Ausdrücke im Arrayinitialisierer bestimmt die Länge der arrayinstanz, die erstellt wird.

Beispiel: Der obige Arrayinitialisierer erstellt eine int[] Instanz der Länge 5 und initialisiert dann die Instanz mit den folgenden Werten:

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

Endbeispiel

Bei einem mehrdimensionalen Array muss der Arrayinitialisierer so viele Schachtelungsebenen aufweisen, wie dimensionen im Array vorhanden sind. Die äußerste Schachtelungsebene entspricht der äußersten Dimension ganz links, und die innerste Schachtelungsebene entspricht der ganz rechts stehenden Dimension. Die Länge jeder Dimension des Arrays wird durch die Anzahl der Elemente auf der entsprechenden Schachtelungsebene im Arrayinitialisierer bestimmt. Für jeden geschachtelten Arrayinitialisierer muss die Anzahl der Elemente mit den anderen Arrayinitialisierern auf derselben Ebene identisch sein.

Beispiel: Das Beispiel:

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

erstellt ein zweidimensionales Array mit einer Länge von fünf für die äußerst linke Dimension und eine Länge von zwei für die äußerst rechte Dimension:

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

und initialisiert dann die Arrayinstanz mit den folgenden Werten:

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;

Endbeispiel

Wenn eine andere Dimension als die äußerst rechte Dimension mit der Länge Null angegeben wird, wird davon ausgegangen, dass die nachfolgenden Dimensionen ebenfalls die Länge Null aufweisen.

Beispiel:

int[,] c = {};

erstellt ein zweidimensionales Array mit einer Länge von Null sowohl für die äußerste linke als auch für die äußerst rechte Dimension:

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

Endbeispiel

Wenn ein Arrayerstellungsausdruck sowohl explizite Dimensionslängen als auch ein Arrayinitialisierer enthält, müssen die Längen konstanten Ausdrücke sein, und die Anzahl der Elemente auf jeder Schachtelungsebene entspricht der entsprechenden Dimensionslänge.

Beispiel: Hier sind einige Beispiele:

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 führt der Initialisierer zu y einem Kompilierungszeitfehler, da der Bemaßungslängenausdruck keine Konstante ist, und der Initialisierer für z ergebnisse in einem Kompilierungszeitfehler, da die Länge und die Anzahl der Elemente im Initialisierer nicht übereinstimmen.

Endbeispiel

Hinweis: C# ermöglicht ein nachfolgendes Komma am Ende eines array_initializer. Diese Syntax bietet Flexibilität beim Hinzufügen oder Löschen von Mitgliedern aus einer solchen Liste und vereinfacht die Computergenerierung solcher Listen. Endnote