Sdílet prostřednictvím


18 Rozšířené indexování a řezy

18.1 Obecné

Tato klauzule zavádí model pro rozšířené indexovatelné a průřezové typy kolekcí založené na těchto typech:

  • Typy uvedené v této klauzuli System.Index (§18.2) a System.Range (§18.3);
  • Předdefinované unární ^ operátory (§12.9.6) a binární .. operátory (§12.10) a
  • Výraz element_access .

Pod modelem je typ klasifikován jako:

  • a collection if it represent a group of elements
  • rozšířenou indexovatelnou kolekci, pokud podporuje výraz element_access, který má jediný argument výraz typuIndex, který vrací nebo nastaví jeden prvek typu, a to buď podle hodnoty, nebo odkazu;
  • rozšířenou kolekci s možností průřezu, pokud podporuje výraz element_access, který má jediný argumentový výraz typuRange, který vrací řez prvků typu podle hodnoty.

Poznámka: Model nevyžaduje, aby byl řez typu nastaven, ale typ ho může podporovat jako rozšíření modelu. koncová poznámka

Model je podporován pro jednorozměrná pole (§12.8.12.2) a řetězce (§12.8.12.3).

Model může být podporován jakoukoli třídou, strukturou nebo typem rozhraní, které poskytují vhodné indexery (§15.9), které implementují sémantiku modelu.

Implicitní podpora modelu je poskytována pro typy, které jej přímo nepodporují, ale které poskytují určitý vzor členů (§18.4). Tato podpora je založená na vzorech, nikoli na sémantickém základě, protože se předpokládá sémantika členů typu, na kterých je založená , – jazyk nevynucuje ani nekontroluje sémantiku těchto členů typu.

Pro účely této klauzule jsou definovány následující termíny:

  • Kolekce je typ, který představuje skupinu prvků.
  • Počítaná kolekce je jedna, která poskytuje počítanou vlastnostint-valued instance, jejíž hodnota je počet prvků aktuálně ve skupině. Tato vlastnost má název buď Length nebo Count. První možnost je zvolena, pokud existují obě.
  • Posloupnost nebo indexovatelný typ je kolekce:
    • což je počítáno;
    • kde každý prvek lze získat přístup pomocí výrazu element_access s jedním povinným int argumentem, index from-start, další volitelné argumenty jsou povoleny;
    • sekvence je upravitelná , pokud lze každý prvek nastavit také pomocí výrazu element_access ;
    • Index od začátku prvku je počet prvků před ním v posloupnosti pro sekvenci obsahující prvky N :
      • první a poslední prvky mají indexy 0 a N-1 a
      • index, který představuje hypotetický prvek za posledním indexem, má hodnotu N.
  • Od-endový index představuje pozici elementu v posloupnosti vzhledem k předchozímu indexu. Pro sekvenci obsahující N prvků jsou první, poslední a poslední-endové indexy N, 1 a 0 v uvedeném pořadí.
  • Rozsah je souvislý běh nulových nebo více indexů začínajících v libovolném indexu v posloupnosti.
  • Řez je kolekce prvků v rozsahu.
  • Průřezová kolekce je ta, která:
    • je počítán;
    • poskytuje metodu Slice , která přebírá dva int parametry určující rozsah, jako počáteční index a počet prvků v uvedeném pořadí, a vrátí nový řez vytvořený z prvků v oblasti.

Výše uvedené definice jsou rozšířeny pro použití Index a Range následujícím způsobem:

  • Typ je také posloupnost , pokud je podporován výraz element_access s jedním povinným Index argumentem, nikoli argumentem int . V případě, že je požadováno rozlišení, je typ označen jako rozšířený indexable.
  • Typ je také průřezovatelný , pokud je podporován výraz element_access s jedním povinným Range argumentem, spíše metodou Slice . V případě, že je požadováno rozlišení, je typ označen jako rozšířený průřez.

Určuje, zda je typ klasifikován jako počítaný, indexovatelný nebo průřez, podléhá omezením přístupnosti členů (§7.5), a proto závisí na tom, kde se typ používá.

Příklad: Typ, ve kterém je počítaná vlastnost nebo indexer protected , je pouze posloupnost členů samotného a všech odvozených typů. konec příkladu

Požadované členy pro typ, které se dají kvalifikovat jako posloupnost nebo průřez, mohou být zděděné.

příklad: V následujícím kódu

public class A
{
    public int Length { get { … } }
}

public class B : A
{
    public int this(int index) { … }
}

public class C : B
{
    public int[] Slice(int index, int count) { … }
}

Typ A je počítán, B je posloupnost a C je průřez a posloupnost.

konec příkladu

Poznámka:

  • Typ může být průřezový, aniž by byl indexovatelný kvůli nedostatku indexeru (přístupného).
  • Aby byl typ průřezový nebo indexovatelný, vyžaduje, aby byl typ počítán.
  • Zatímco prvky sekvence jsou seřazeny podle pozice v posloupnosti, samotné prvky nemusí být seřazeny podle jejich hodnoty nebo dokonce seřazené.

koncová poznámka

18.2 Typ indexu

Typ System.Index představuje abstraktní index, který představuje index od začátku nebo od koncového indexu.

    public readonly struct Index : IEquatable<Index>
    {
        public int Value { get; }
        public bool IsFromEnd { get; }

        public Index(int value, bool fromEnd = false);

        public static implicit operator Index(int value);
        public int GetOffset(int length);
        public bool Equals(Index other);
    }

Index hodnoty jsou tvořeny z inthodnoty , určení ne záporného posunu a a bool, označující, zda je posun od konce (true) nebo začátku (false). Pokud je zadaný posun záporný, ArgumentOutOfRangeException vyvolá se.

Příklad

Index first = new Index(0, false); // first element index
var last = new Index(1, true);     // last element index
var past = new Index(0, true);     // past-end index

Index invalid = new Index(-1);     // throws ArgumentOutOfRangeException

konec příkladu

Existuje implicitní převod, ze intIndex kterého vznikají počáteční indexy, a jazykově definovaný unární operátor ^ (§12.9.6), ze intIndex kterého se vytváří indexy od konce.

Příklad

Pomocí implicitních převodů a unárního ^ operátoru mohou být zapsány výše uvedené příklady:

Index first = 0; // first element index
var last = ^1;   // last element index
var past = ^0;   // past-end index

konec příkladu

Metoda GetOffset převede z abstraktní Index hodnoty na konkrétní int hodnotu indexu pro sekvenci zadaného length. Pokud hodnota Index , Ije od-end tato metoda vrátí stejnou hodnotu jako length - I.Value, jinak vrátí stejnou hodnotu jako I.Value.

Tato metoda nekontroluje , že vrácená hodnota je v platném rozsahu 0length-1 včetně.

Poznámka: Není zadána žádná kontrola, protože očekávané použití výsledku je indexovat do sekvence s length prvky a že se očekává, že operace indexování provede příslušné kontroly. koncová poznámka

Index implements IEquatable<Index> and values may be compared for equal on the abstract value; two Index values are equal if and only if the respective Value and IsFromEnd properties are equal. Hodnoty ale Index nejsou seřazené a nejsou k dispozici žádné jiné operace porovnání.

Poznámka:Index hodnoty jsou neuspořádané, protože jsou abstraktní indexy, obecně není možné určit, zda před nebo po počátečním indexu pochází před nebo po počátečním indexu bez odkazu na délku sekvence. Po převodu na konkrétní indexy jsou tyto GetOffsetkonkrétní indexy srovnatelné. koncová poznámka

Index hodnoty mohou být použity přímo ve argument_listvýrazu element_access (§12.8.12), který je:

  • přístup k poli a cíl je jednorozměrná matice (§12.8.12.2);
  • přístup k řetězci (§12.8.12.3)
  • přístup k indexeru a cílový typ má indexer s odpovídajícími parametry typu Index (§12.8.12.4) nebo typu, na který Index jsou hodnoty implicitně konvertibilní;
  • přístup indexeru a cílový typ odpovídá sekvenci, pro který je určena implicitní Index podpora (§18.4.2).

18.3 Typ rozsahu

Typ System.Range představuje abstraktní rozsah hodnot z indexu IndexStart až do indexu, ale ne zahrnutí indexuEnd.

    public readonly struct Range : IEquatable<Index>
    {
        public Index Start { get; }
        public Index End { get; }

        public Range(Index start, Index end);

        public (int Offset, int Length) GetOffsetAndLength(int length);
        public bool Equals(Range other);
    }

Range hodnoty jsou tvořeny ze dvou Index hodnot.

Příklad

Následující příklady používají implicitní převod na intIndex (§18.2) a ^ operátor (§12.9.6) k vytvoření Index hodnot pro každý Range:

var firstQuad = new Range(0, 4);  // the indices from `0` to `3`
                                  // int values impicitly convert to `Index`
var nextQuad = new Range(4, 8);   // the indices from `4` to `7`
var wholeSeq = new Range(0, ^0);  // the indices from `0` to `N-1` where `N` is the
                                  // length of the sequence wholeSeq is used with
var dropFirst = new Range(1, ^0); // the indices from `1` to `N-1`
var dropLast = new Range(0, ^1);  // the indices from `0` to `N-2`
var maybeLast = new Range(^1, 6); // the indices from `N-1` to 5
var lastTwo = new Range(^2, ^0);  // the indices from `N-2` to `N-1`

konec příkladu

Operátor definovaný .. jazykem (§12.10) vytvoří Range hodnotu z Index hodnot.

Příklad

Použití operátoru .. výše uvedených příkladů může být zapsáno:

var firstQuad = 0..4;  // the indices from `0` to `3`
var nextQuad = 4..8;   // the indices from `4` to `7`
var wholeSeq = 0..^0;  // the indices from `0` to `N-1`
var dropFirst = 1..^0; // the indices from `1` to `N-1`
var dropLast = 0..^1;  // the indices from `0` to `N-2`
var maybeLast = ^1..6; // the indices from `N-1` to 5
var lastTwo = ^2..^0;  // the indices from `N-2` to `N-1`

konec příkladu

Operandy .. jsou volitelné, první výchozí hodnota 0, druhá výchozí hodnota ^0.

Příklad

Pět z výše uvedených příkladů je možné zkrátit tím, že se spoléhá na výchozí hodnoty pro operandy:

var firstQuad = ..4; // the indices from `0` to `3`
var wholeSeq = ..;   // the indices from `0` to `N-1`
var dropFirst = 1..; // the indices from `1` to `N-1`
var dropLast = ..^1; // the indices from `0` to `N-2`
var lastTwo = ^2..;  // the indices from `N-2` to `N-1`

konec příkladu

Hodnota Range je platná s ohledem na délku L , pokud:

  • konkrétní indexy s ohledem na LRange vlastností Start a End jsou v rozsahu 0 až L; a
  • konkrétní index Start není větší než konkrétní index pro End

Metoda GetOffsetAndLength s argumentem length převede abstraktní Range hodnotu na konkrétní Range hodnotu reprezentovanou řazenou kolekcí členů. Range Pokud není platný s ohledem na length metodu vyvolá ArgumentOutOfRangeException.

Vrácená betonová Range řazená kolekce členů je dvojice formuláře (S, N) , kde:

  • S je počáteční posun rozsahu, který je betonovým indexem Start pro vlastnost Range; a
  • N je počet položek v rozsahu, přičemž je rozdíl mezi konkrétními indexy pro End vlastnosti a Start vlastnostmi;
  • obě hodnoty se počítají s ohledem na length.

Konkrétní hodnota rozsahu je prázdná , pokud N je nula. Prázdný rozsah betonu S může mít hodnotu rovnající se konkrétnímu minulému indexu (§18.1), neprázdný rozsah nesmí. Pokud je kolekce použitá Range k řezu (§18.1), je kolekce platná a prázdná s ohledem na tuto kolekci, je výsledný řez prázdnou kolekcí.

Poznámka: Výsledkem výše uvedeného je, že Range hodnota, která je platná a prázdná s ohledem na nulu length , může být použita k řezu prázdné kolekce a výsledkem je prázdný řez. Liší se od indexování, které vyvolá výjimku, pokud je kolekce prázdná. koncová poznámka*

Příklad

Použití výše definovaných proměnných s GetOffSetAndLength(6):

var (ix0, len0) = firstQuad.GetOffsetAndLength(6); // ix0 = 0, len0 = 4
var (ix1, len1) = nextQuad.GetOffsetAndLength(6);  // throws
   // ArgumentOutOfRangeException as range crosses sequence end
var (ix2, len2) = wholeSeq.GetOffsetAndLength(6);  // ix2 = 0, len2 = 6
var (ix3, len3) = dropFirst.GetOffsetAndLength(6); // ix3 = 1, len3 = 5
var (ix4, len4) = dropLast.GetOffsetAndLength(6);  // ix4 = 0, len4 = 5
var (ix5, len5) = maybeLast.GetOffsetAndLength(6); // ix5 = 5, len5 = 1
var (ix6, len6) = lastTwo.GetOffsetAndLength(6);   // ix6 = 4, len6 = 2

Range implements IEquatable<Range> and values may be compared for equal on the abstract value; two Range values are equal if and only if the abstract values of the respective Start and End properties are equal (§18.2). Hodnoty ale Range nejsou seřazené a nejsou k dispozici žádné jiné operace porovnání.

Poznámka:Range hodnoty jsou neuspořádané, protože jsou abstraktní a neexistuje žádná jedinečná relace řazení. Po převodu na konkrétní začátek a délku může GetOffsetAndLengthbýt definována například relace řazení. koncová poznámka

Range hodnoty lze použít přímo ve argument_listvýrazu element_access (§12.8.12), který je:

  • přístup k poli a cíl je jednorozměrná matice (§12.8.12.2);
  • přístup k řetězci (§12.8.12.3);
  • přístup k indexeru a cílový typ má indexer s odpovídajícími parametry typu Range (§12.8.12.4) nebo typu, na který Range jsou hodnoty implicitně konvertibilní;
  • přístup indexeru (§12.8.12.4) a cílový typ odpovídá sekvenci, pro který je zadána implicitní Range podpora (§18.4.3).

18.4 Implicitní podpora založené na vzorech pro index a rozsah

18.4.1 Obecné

Je-li výraz element_access (§12.8.12) formuláře E[A]; pokud E má typ T a A je jedním výrazem implicitně konvertibilní na Index nebo Range; nelze identifikovat jako:

pak je k dispozici implicitní podpora výrazu, pokud T odpovídá určitému vzoru. Pokud T tento vzor nevyhovuje, dojde k chybě v době kompilace.

Podpora implicitního indexu 18.4.2

Pokud v libovolném kontextu není výraz element_access (§12.8.12) formuláře E[A]; pokud E má typ T a A je jedním výrazem implicitně konvertibilní Indexna ; není platný (§18.4.1), pak pokud je ve stejném kontextu:

  • T poskytuje přístupné členy, kteří je opravňující jako posloupnost (§18.1); a
  • výraz E[0] je platný a používá stejný indexer, který se kvalifikuje T jako posloupnost.

pak se výraz E[A] implicitně podporuje.

Bez jinak omezujících implementací této normy se pořadí vyhodnocení výrazu rovná:

  1. E vyhodnocuje se;
  2. A vyhodnocuje se;
  3. počítaná vlastnost T se vyhodnocuje, pokud je to požadováno implementací;
  4. Vyvolá se get nebo set přístupového objektu int založeného na indexeru T , který by byl použit E[0] ve stejném kontextu.

Podpora implicitního rozsahu 18.4.3

Pokud v libovolném kontextu není výraz element_access (§12.8.12) formuláře E[A]; pokud E má typ T a A je jedním výrazem implicitně konvertibilní Rangena ; není platný (§18.4.1), pak pokud je ve stejném kontextu:

  • T poskytuje přístupné členy, které jsou kvalifikující jako spočítatelné i průřezové (§18.1).

pak se výraz E[A] implicitně podporuje.

Bez jinak omezujících implementací této normy se pořadí vyhodnocení výrazu rovná:

  1. E vyhodnocuje se;
  2. A vyhodnocuje se;
  3. počítaná vlastnost T se vyhodnocuje, pokud je to požadováno implementací;
  4. Slice metoda T je vyvolána.