Megosztás a következőn keresztül:


17 Tömbök

17.1 Általános

A tömb olyan adatstruktúra, amely számos olyan változót tartalmaz, amelyek számítási indexeken keresztül érhetők el. A tömbben található változók, más néven a tömb elemei mind azonos típusúak, és ezt a típust a tömb elemtípusának nevezzük.

A tömbök rangsora határozza meg az egyes tömbelemekhez társított indexek számát. A tömb rangját a tömb dimenzióinak is nevezik. Egy rangot tartalmazó tömböt egydimenziós tömbnek nevezünk. Az egynél nagyobb rangot tartalmazó tömböt többdimenziós tömbnek nevezzük. Az adott méretű többdimenziós tömböket gyakran kétdimenziós tömböknek, háromdimenziós tömböknek és így tovább nevezik. A tömbök minden dimenziójának van egy társított hossza, amely egy nullánál nagyobb vagy egyenlő egész szám. A dimenzióhosszok nem részei a tömb típusának, hanem akkor jönnek létre, ha a tömbtípus egy példánya futásidőben jön létre. A dimenzió hossza határozza meg az adott dimenzióra vonatkozó indexek érvényes tartományát: Hosszúsági dimenziók Nesetén az indexek a befogadótól a 0 N – 1 befogadóig terjedhetnek. A tömb elemeinek teljes száma a tömb egyes dimenzióinak hosszának szorzata. Ha egy tömb egy vagy több dimenziója nulla hosszúságú, akkor a tömb üresnek minősül.

A tömb elemtípusa lehet tömbtípus (17.2.1. §). Az ilyen tömbök különböznek a többdimenziós tömböktől, és "szaggatott tömbök" ábrázolására használhatók.

Példa:

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

záró példa

Minden tömbtípus egy referenciatípus (8.2. §). A tömb elemtípusa bármilyen típusú lehet, beleértve az értéktípusokat és a tömbtípusokat is.

17.2 Tömbtípusok

17.2.1 Általános

A tömbtípusok nyelvtani termelését a 8.2.1.

A tömbtípusokat non_array_type egy vagy több rank_specifierkövet.

A non_array_type minden olyan típus , amely nem maga array_type.

A tömbtípus rangját a array_type bal szélső rank_specifier adja meg: A rank_specifier azt jelzi, hogy a tömb egy egy és a rank_specifier "" jogkivonatainak száma,.

A tömbtípus elemtípusa az a típus, amely a bal szélső rank_specifier törléséből ered:

  • Az űrlap T[R] tömbtípusa egy ranggal R rendelkező tömb és egy nem tömbelem típusú T.
  • Az űrlap T[R][R₁]...[Rₓ] tömbtípusa egy ranggal R és elemtípussal T[R₁]...[Rₓ]rendelkező tömb.

Valójában a rank_specifiers-eket a rendszer balról jobbra olvassa be a végső nem tömbelem-típus előtt .

Példa: A típus egydimenziós T[][,,][,] tömb, amely a kétdimenziós tömbök háromdimenziós tömbjeiből áll int. záró példa

Futtatáskor egy tömbtípus értéke vagy null hivatkozás lehet az adott tömbtípus egy példányára.

Megjegyzés: A 17.6. §-nak megfelelően az érték egy kovariant tömbtípusra való hivatkozás is lehet. végjegyzet

17.2.2 A System.Array típusa

A típus System.Array az összes tömbtípus absztrakt alaptípusa. Implicit referenciakonvertálás (10.2.8. §) létezik bármilyen tömbtípusból System.Array a System.Array. Explicit referenciakonvertálás (10.3.5.§) létezik, System.Array és bármilyen felülettípust System.Array implementál bármilyen tömbtípusra. System.Arraynem array_type. Inkább egy class_type , amelyből az összes array_typeszármazik.

Futtatáskor a típus System.Array értéke bármilyen tömbtípus egy példányára hivatkozhat null .

17.2.3 Tömbök és az általános gyűjtőfelületek

Egy egydimenziós tömb T[] implementálja az interfészt System.Collections.Generic.IList<T> (IList<T> röviden) és alapillesztőit. Ennek megfelelően implicit átalakítás történik a kezdő IList<T> és annak alapfelületei közöttT[]. Továbbá, ha implicit referencia-átalakítás S T történik, akkor S[] implementálja IList<T> a műveletet, és implicit referenciaátalakítás történik a kezdő IList<T> és annak alapfelületei között S[] (10.2.8. §). Ha explicit referenciakonvertálásról van szó, akkor a referenciakonvertálás S T a cél és annak alapfelületei között IList<T> S[] történik (10.3.5. §).

Hasonlóképpen egy egydimenziós tömb T[] is implementálja az interfészt System.Collections.Generic.IReadOnlyList<T> (IReadOnlyList<T> röviden) és az alapillesztőit. Ennek megfelelően implicit átalakítás történik a kezdő IReadOnlyList<T> és annak alapfelületei közöttT[]. Továbbá, ha implicit referencia-átalakítás S T történik, akkor S[] implementálja IReadOnlyList<T> a műveletet, és implicit referenciaátalakítás történik a kezdő IReadOnlyList<T> és annak alapfelületei között S[] (10.2.8. §). Ha explicit referenciakonvertálásról van szó, akkor a referenciakonvertálás S T a cél és annak alapfelületei között IReadOnlyList<T> S[] történik (10.3.5. §).

Példa: Például:

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

A hozzárendelés lst2 = oa1 fordítási időt eredményez, mivel a konvertálás object[] IList<string> explicit, nem implicit átalakítás. A szereposztás (IList<string>)oa1 kivételt okoz futásidőben, mivel oa1 object[] nem string[]a . Azonban a leadott (IList<string>)oa2 nem okoz kivételt kell dobni, mivel oa2 hivatkozik a string[].

záró példa

Amikor implicit vagy explicit referenciakonvertálásról van szó, explicit referenciakonvertálás S[] IList<T>is történik a forrásból és annak alapfelületéről IList<T> S[] (10.3.5. §).

Amikor egy tömbtípus S[] implementál IList<T>, a implementált felület egyes tagjai kivételeket okozhatnak. Az interfész implementálásának pontos viselkedése meghaladja a jelen specifikáció hatókörét.

17.3 Tömb létrehozása

A tömbpéldányokat array_creation_expression s (12.8.16.5. §) vagy egy array_initializer tartalmazó mező- vagy helyi változódeklaráció (17.7. §) hozza létre. A tömbpéldányok implicit módon is létrehozhatók egy paramétertömböt tartalmazó argumentumlista kiértékelésének részeként (15.6.2.4. §).

Tömbpéldány létrehozásakor a rendszer létrehozza az egyes dimenziók rangját és hosszát, majd állandó marad a példány teljes élettartama alatt. Más szóval nem lehet módosítani egy meglévő tömbpéldány rangját, és a méreteit sem lehet átméretezni.

A tömbpéldányok mindig tömbtípusúak. A System.Array típus olyan absztrakt típus, amely nem hozható létre.

Az array_creation_expressionáltal létrehozott tömbök elemei mindig az alapértelmezett értékükre vannak inicializálva (9.3. §).

17.4 Tömbelem-hozzáférés

A tömbelemek az űrlap A[I₁, I₂, ..., Iₓ]element_access kifejezései (§12.8.11.2) használatával érhetők el, ahol A egy tömbtípus kifejezése, és mindegyik Iₑ típuskifejezésint, uintlongvagy ulongimplicit módon konvertálható egy vagy több ilyen típusra. A tömbelem-hozzáférés eredménye egy változó, nevezetesen az indexek által kiválasztott tömbelem.

A tömb elemei egy utasítással foreach számba vehetők (13.9.5. §).

17.5 Tömbtagok

Minden tömbtípus örökli a típus által System.Array deklarált tagokat.

17.6 Tömb kovariancia

Bármely két reference_type esetében, és Bha implicit referenciaátalakítás (10.2.8. §) vagy explicit referenciakonvertálás (10.3.5. §) létezik A B, akkor ugyanez a hivatkozási átalakítás a tömbtípustól A[R] a tömbtípusig B[R]is létezik, ahol R bármely adott rank_specifier (de mindkét tömbtípus esetében ugyanaz).A Ezt a kapcsolatot tömb-kovariancia néven ismerjük. A tömb kovariancia különösen azt jelenti, hogy egy tömbtípus A[R] értéke valójában egy tömbtípus B[R]egy példányára való hivatkozás lehet, feltéve, hogy implicit hivatkozási átalakítás létezik a B helyről a másikra A.

A tömbök kovariancia miatt a referencia típusú tömbök elemeihez való hozzárendelések futásidejű ellenőrzést tartalmaznak, amely biztosítja, hogy a tömbelemhez hozzárendelt érték ténylegesen engedélyezett típusú legyen (12.21.2. §).

Példa:

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

A metódushoz való array[i] Fill hozzárendelés implicit módon tartalmaz egy futásidejű ellenőrzést, amely biztosítja, hogy value null egy hivatkozás vagy hivatkozás egy olyan típusú objektumra, amely kompatibilis a tényleges elemtípussal array. Ebben Mainaz esetben az első két meghívás Fill sikeres, de a harmadik meghívás hatására System.ArrayTypeMismatchException az első hozzárendelés array[i]végrehajtásakor a program a következőre vált. A kivétel azért fordul elő, mert egy dobozos int nem tárolható tömbben string .

záró példa

A tömb kovariancia nem terjed ki value_typetömbökre. Nincs például olyan átalakítás, amely lehetővé teszi, hogy a int[] rendszer egy object[].

17.7 Tömb inicializálók

Tömb inicializálók megadhatóak meződeklarációkban (15.5.§), helyi változódeklarációkban (13.6.2. §) és tömblétrehozó kifejezésekben (12.8.16.5. §):

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

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

A tömb inicializálói változó inicializálók sorozatából állnak, amelyeket "{" és "}" jogkivonatok, valamint "," jogkivonatok választanak el egymástól. Minden változó inicializáló egy kifejezés, vagy többdimenziós tömb esetén beágyazott tömb inicializáló.

A tömb inicializálójának környezete határozza meg az inicializálandó tömb típusát. A tömblétrehozó kifejezésben a tömbtípus közvetlenül megelőzi az inicializálót, vagy a tömb inicializálójának kifejezéseiből következtet. Egy mező- vagy változódeklarációban a tömb típusa a deklarált mező vagy változó típusa. Ha tömb inicializálót használ egy mezőben vagy változódeklarációban,

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

ez egyszerűen rövidítés egy egyenértékű tömblétrehozó kifejezéshez:

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

Egydimenziós tömb esetén a tömb inicializálójának kifejezéssorozatból kell állnia, amelyek mindegyike implicit módon konvertálja a tömb elemtípusát (10.2. §). A kifejezések növekvő sorrendben inicializálják a tömbelemeket, kezdve az index nullánál lévő elemével. A tömb inicializálójában lévő kifejezések száma határozza meg a létrehozandó tömbpéldány hosszát.

Példa: A fenti tömb inicializálója létrehoz egy int[] 5 hosszúságú példányt, majd inicializálja a példányt a következő értékekkel:

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

záró példa

Többdimenziós tömb esetén a tömb inicializálójának annyi beágyazási szinttel kell rendelkeznie, mint amennyi dimenzió van a tömbben. A legkülső beágyazási szint a bal szélső dimenziónak felel meg, a legbelső beágyazási szint pedig a jobb szélső dimenziónak felel meg. A tömb minden dimenziójának hosszát a tömb inicializálójának megfelelő beágyazási szinten lévő elemek száma határozza meg. Minden beágyazott tömb inicializáló esetében az elemek számának meg kell egyeznie a többi, azonos szintű tömb inicializálóval.

Példa: A példa:

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

egy kétdimenziós tömböt hoz létre, amelynek bal szélső dimenziója öt, a jobb szélső dimenzióhoz pedig kettő:

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

majd inicializálja a tömbpéldányt a következő értékekkel:

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;

záró példa

Ha a jobb szélső dimenziótól eltérő dimenziót nullával adnak meg, akkor a következő dimenziók is nulla hosszúságúak lesznek.

Példa:

int[,] c = {};

létrehoz egy kétdimenziós tömböt, amelynek a bal szélső és a jobb szélső dimenziója is nulla hosszúságú:

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

záró példa

Ha egy tömblétrehozási kifejezés explicit dimenzióhosszokat és tömbinicializálót is tartalmaz, a hosszoknak állandó kifejezéseknek kell lenniük, és az egyes beágyazott szinteken lévő elemek számának meg kell egyeznie a megfelelő dimenzióhosszsal.

Példa: Íme néhány példa:

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

Ebben az esetben az inicializáló y fordítási idejű hibát eredményez, mivel a dimenzióhossz-kifejezés nem állandó, az eredmények inicializálója z pedig fordítási idő hibába ütközik, mert az inicializáló hossza és az elemek száma nem egyezik meg.

záró példa

Megjegyzés: A C# lehetővé teszi a záró vesszőt egy array_initializer végén. Ez a szintaxis rugalmasságot biztosít a tagok hozzáadásához vagy törléséhez egy ilyen listából, és leegyszerűsíti az ilyen listák gépi létrehozását. végjegyzet