Freigeben über


18 Erweiterte Indizierung und Slicing

18.1 Allgemein

In dieser Klausel wird ein Modell für erweiterte indizierbare und datenschnittfähigeAuflistungstypen eingeführt, die auf:

  • Die in dieser Klausel eingeführten System.Index Typen (§18.2) und System.Range (§18.3);
  • Die vordefinierten unär ^ (§12.9.6) und binären .. Operatoren (§12.10) und
  • Der element_access Ausdruck.

Unter dem Modell wird ein Typ wie folgt klassifiziert:

  • eine Auflistung , wenn sie eine Gruppe von Elementendarstellt
  • eine erweiterte indizierbare Auflistung, wenn sie einen element_access Ausdruck unterstützt, der über einen einzelnen Argumentausdruck vom Typ Index verfügt, der ein einzelnes Element des Typs zurückgibt und/oder ein einzelnes Element des Typs zurückgibt, entweder nach Wert oder nach Bezug;
  • eine erweiterte datenschnittfähige Auflistung, wenn sie einen element_access Ausdruck unterstützt, der einen einzelnen Argumentausdruck vom Typ Range aufweist, der ein Segment der Elemente des Typs nach Wert zurückgibt.

Hinweis: Das Modell erfordert nicht, dass ein Segment des Typs festgelegt werden kann, aber ein Typ kann es als Erweiterung des Modells unterstützen. Hinweisende

Das Modell wird für eindimensionale Arrays (§12.8.12.2) und Zeichenfolgen (§12.8.12.3) unterstützt.

Das Modell kann von jeder Klasse, Struktur oder einem Schnittstellentyp unterstützt werden, die geeignete Indexer (§15.9) bereitstellt, die die Modellsemantik implementieren.

Implizite Unterstützung für das Modell wird für Typen bereitgestellt, die es nicht direkt unterstützen, aber ein bestimmtes Muster von Membern (§18.4) bereitstellen. Diese Unterstützung ist musterbasiert und nicht semantisch, da die Semantik der Typenmmber, auf denen sie basiert, angenommen werden – die Sprache erzwingt oder überprüft nicht die Semantik dieser Typm.

Für die Zwecke dieser Klausel werden die folgenden Begriffe definiert:

  • Eine Auflistung ist ein Typ, der eine Gruppe von Elementendarstellt.
  • Eine zählbare Auflistung ist eine Auflistung, die eine zählungsfähige Eigenschaft für eine intInstanzeigenschaft mit Einem Wert bereitstellt, deren Wert die Anzahl der Elemente ist, die sich derzeit in der Gruppe befinden. Diese Eigenschaft muss entweder Length oder Count. Das Erste wird ausgewählt, wenn beide vorhanden sind.
  • Eine Sequenz oder ein indizierbarer Typ ist eine Auflistung:
    • was gezählt werden kann;
    • wenn auf jedes Element mithilfe eines element_access Ausdrucks mit einem einzigen erforderlichen int Argument zugegriffen werden kann, sind von Anfang an zusätzliche optionale Argumente zulässig;
    • Eine Sequenz kann geändert werden, wenn jedes Element auch mit einem element_access Ausdruck festgelegt werden kann;
    • Der Ausgangsindex eines Elements ist die Anzahl der Elemente, die in der Sequenz vorhanden sind, für eine Sequenz, die N-Elemente enthält:
      • die ersten und letzten Elemente haben Indizes von 0 bzw. N-1, und
      • der Past-End-Index, ein Index, der ein hypothetisches Element nach dem letzten darstellt, hat den Wert N.
  • Ein From-End-Index stellt die Position eines Elements innerhalb einer Sequenz relativ zum Past-End-Index dar. Für eine Sequenz, die N-Elemente enthält, sind die Indizes "erster", "last" und "past-end" jeweils "N", "1" bzw. "0".
  • Ein Bereich ist eine zusammenhängende Zeichenfolge von null oder mehr Indizes, die mit einem beliebigen Index innerhalb einer Sequenz beginnen.
  • Ein Segment ist die Sammlung von Elementen innerhalb eines Bereichs.
  • Eine datenschnittfähige Sammlung ist eine der:
    • ist zählbar;
    • stellt eine Methode Slice bereit, die zwei int Parameter angibt, die einen Bereich angeben, wobei es sich um einen Anfangsindex und eine Anzahl von Elementen handeln soll, und gibt ein neues Segment zurück, das aus den Elementen im Bereich erstellt wurde.

Die vorstehenden Definitionen werden für die Verwendung von Index und Range wie folgt erweitert:

  • Ein Typ ist auch eine Sequenz , wenn ein element_access Ausdruck, der ein einzelnes erforderliches Index Argument anstelle eines int Arguments verwendet, unterstützt wird. Wenn eine Unterscheidung erforderlich ist, wird der Typ als erweitert indiziert.
  • Ein Typ kann auch segmentierbar sein, wenn ein element_access Ausdruck, der ein einzelnes erforderliches Range Argument verwendet, sondern eine Slice Methode unterstützt wird. Wenn eine Unterscheidung erforderlich ist, wird der Typ als erweiterter Datenschnitt bezeichnet.

Ob ein Typ als zählbar, indizierbar oder segmentierbar klassifiziert wird, unterliegt den Einschränkungen der Barrierefreiheit von Membern (§7.5) und hängt daher davon ab, wo der Typ verwendet wird.

Beispiel: Ein Typ, bei dem die zählende Eigenschaft und/oder der Indexer nur eine Sequenz zu Elementen von sich selbst und allen abgeleiteten Typen sind protected . Ende des Beispiels

Die erforderlichen Member für einen Typ, die als Sequenz oder Datenschnitt qualifiziert werden können, können geerbt werden.

Beispiel: Im folgenden Code

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) { … }
}

Der Typ A kann gezählt werden, B ist eine Sequenz und C ist datenschnittfähig und eine Sequenz.

Ende des Beispiels

Note:

  • Ein Typ kann segmentierbar sein, ohne dass er indiziert werden kann, da kein (barrierefreier) Indexer fehlt.
  • Damit ein Typ datenschnittfähig und/oder indiziert werden kann, muss der Typ gezählt werden.
  • Während die Elemente einer Sequenz nach Position innerhalb der Sequenz sortiert werden, müssen die Elemente selbst nicht nach ihrem Wert sortiert oder sogar sortiert werden.

Hinweisende

18.2 Der Indextyp

Der System.Index Typ stellt einen abstrakten Index dar, der entweder einen From-Start-Index oder einen From-End-Index darstellt.

    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 Werte werden aus einem int, der den nicht negativen Offset angibt, und ein bool, der angibt, ob der Offset vom Ende (true) oder vom Anfang (false) liegt. Wenn der angegebene Offset negativ ist, wird ein ArgumentOutOfRangeException Fehler ausgelöst.

Beispiel

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

Ende des Beispiels

Es gibt eine implizite Konvertierung, von intIndex der ausgehende Indizes erzeugt werden, und ein sprachdefinierter unärer Operator ^ (§12.9.6), von dem aus intIndex Endindizes erzeugt werden.

Beispiel

Die Verwendung impliziter Konvertierungen und des unären ^ Operators können die obigen Beispiele geschrieben werden:

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

Ende des Beispiels

Die Methode GetOffset konvertiert von einem abstrakten Index Wert in einen konkreten int Indexwert für eine Sequenz der angegebenen length. Wenn der Index Wert von Ende ist, Igibt diese Methode denselben Wert wie length - I.Value, andernfalls gibt sie denselben Wert wie I.Value.

Mit dieser Methode wird nicht überprüft, ob sich der Rückgabewert im gültigen Bereich von 0length-1 einschließlich (einschließlich) befindet.

Anmerkung: Es wird keine Überprüfung angegeben, da die erwartete Verwendung des Ergebnisses darin besteht, eine Sequenz mit length Elementen indizieren zu können, und dass der Indizierungsvorgang die entsprechenden Prüfungen durchführt. Hinweisende

Index implementiert und Werte können auf der Grundlage des abstrakten Werts IEquatable<Index> für Gleichheit verglichen werden. Zwei Index Werte sind gleich, wenn und nur, wenn die jeweiligen Value und IsFromEnd Eigenschaften gleich sind. Werte werden jedoch Index nicht sortiert, und es werden keine anderen Vergleichsvorgänge bereitgestellt.

Anmerkung:Index Werte sind ungeordnet, da sie abstrakte Indizes sind, ist es im Allgemeinen unmöglich zu bestimmen, ob ein From-End-Index vor oder nach einem Von Startindex ohne Verweis auf eine Sequenzlänge kommt. Nach der Umwandlung in betonierte Indizes, z.B. durch GetOffset, sind diese konkreten Indizes vergleichbar. Hinweisende

Index Werte können direkt in der argument_list eines element_access Ausdrucks (§12.8.12) verwendet werden, der wie folgt lautet:

  • ein Arrayzugriff und das Ziel ist ein eindimensionales Array (§12.8.12.2);
  • Zeichenfolgenzugriff (§12.8.12.3)
  • ein Indexerzugriff und der Zieltyp verfügt über einen Indexer mit entsprechenden Parametern des Typs Index (§12.8.12.4) oder eines Typs, für den Index Werte implizit konvertierbar sind;
  • ein Indexerzugriff und der Zieltyp entsprechen einem Sequenzmuster, für das implizite Index Unterstützung angegeben wird (§18.4.2).

18.3 Der Bereichstyp

Der System.Range Typ stellt den abstrakten Bereich von Indexes von einem Start Index bis zu, aber nicht einschließlich eines End Indexes.

    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 Werte werden aus zwei Index Werten erstellt.

Beispiel

In den folgenden Beispielen wird die implizite Konvertierung von int zu Index (§18.2) und dem ^ (§12.9.6)-Operator verwendet, um die Index Werte für die einzelnen Rangezu erstellen:

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`

Ende des Beispiels

Der sprachdefinierte Operator .. (§12.10) erstellt einen Range Wert aus Index Werten.

Beispiel

Mit dem .. Operator können die obigen Beispiele geschrieben werden:

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`

Ende des Beispiels

Die Operanden von .. sind optional, die ersten Standardwerte 0für , die zweite Standardeinstellung ist ^0.

Beispiel

Fünf der obigen Beispiele können durch Die Verwendung von Standardwerten für Operanden gekürzt werden:

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`

Ende des Beispiels

Ein Range Wert ist in Bezug auf eine Länge Lgültig, wenn:

  • die konkreten Indizes in Bezug auf L der Range Eigenschaften Start und End liegen im Bereich 0 bis L;
  • der konkrete Index Start ist nicht größer als der konkrete Index für End

Die Methode GetOffsetAndLength mit einem Argument length konvertiert einen abstrakten Range Wert in einen konkreten Range Wert, der durch Tupel dargestellt wird. Wenn dies Range in Bezug auf length die Methode nicht gültig ist, wird ArgumentOutOfRangeExceptionausgelöst.

Das zurückgegebene Beton-Tupel Range ist ein Paar der Form (S, N) , wobei:

  • S ist der Anfangsoffset des Bereichs, wobei es sich um den konkreten Index für die Start Eigenschaft des RangeBereichs handelt; und
  • Nist die Anzahl der Elemente im Bereich, wobei es sich um den Unterschied zwischen den konkreten Indizes für die und End eigenschaften Start handelt;
  • beide Werte, die in Bezug auf length.

Ein konkreter Bereichswert ist leer , wenn N null ist. Ein leerer Betonbereich kann einen S Wert aufweisen, der dem konkreten Past-End-Index (§18.1) entspricht, ein nicht leerer Bereich darf nicht sein. Wenn eine Range Sammlung, die zum Segment (§18.1) verwendet wird, gültig und leer in Bezug auf diese Sammlung ist, ist das resultierende Segment eine leere Sammlung.

Anmerkung: Dies hat zur Folge, dass ein Range gültiger und leerer Wert in Bezug auf eine length Null verwendet werden kann, um eine leere Auflistung zu segmentieren und zu einem leeren Segment führt. Dies unterscheidet sich von der Indizierung, die eine Ausnahme auslöst, wenn die Auflistung leer ist. Endnote*

Beispiel

Verwenden der oben definierten Variablen mit 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 implementiert und Werte können auf der Grundlage des abstrakten Werts IEquatable<Range> verglichen werden. Zwei Range Werte sind gleich, wenn die abstrakten Werte der jeweiligen Start Werte und End Eigenschaften gleich sind (§18.2). Werte werden jedoch Range nicht sortiert, und es werden keine anderen Vergleichsvorgänge bereitgestellt.

Anmerkung:Range Werte sind ungeordnet, da sie abstrahiert sind und keine eindeutige Sortierbeziehung vorhanden ist. Nach der Umwandlung in einen konkreten Anfangs- und Längenbeginn, z. B. durch GetOffsetAndLength, kann eine Sortierbeziehung definiert werden. Hinweisende

Range Werte können direkt in der argument_list eines element_access Ausdrucks (§12.8.12) verwendet werden, der wie folgt lautet:

  • ein Arrayzugriff und das Ziel ist ein eindimensionales Array (§12.8.12.2);
  • Zeichenfolgenzugriff (§12.8.12.3);
  • ein Indexerzugriff und der Zieltyp verfügt über einen Indexer mit entsprechenden Parametern des Typs Range (§12.8.12.4) oder eines Typs, für den Range Werte implizit konvertierbar sind;
  • ein Indexerzugriff (§12.8.12.4) und der Zieltyp entspricht einem Sequenzmuster, für das implizite Range Unterstützung angegeben wird (§18.4.3).

18.4 Musterbasierte implizite Unterstützung für Index und Bereich

18.4.1 Allgemein

Wenn ein element_access Ausdruck (§12.8.12) des Formulars E[A]; wobei E Typ T hat und A ein einzelner Ausdruck implizit in Index oder Range; nicht identifiziert werden kann als:

dann wird implizite Unterstützung für den Ausdruck bereitgestellt, wenn T es mit einem bestimmten Muster übereinstimmt. Wenn T dieses Muster nicht erfüllt ist, tritt ein Kompilierungszeitfehler auf.

Unterstützung für impliziten Index 18.4.2

Wenn in irgendeinem Kontext ein element_access Ausdruck (§12.8.12) des Formulars E[A]; hat E Typ T und A ist ein einzelner Ausdruck implizit konvertierbar in Index; ist ungültig (§18.4.1), wenn in demselben Kontext:

  • T stellt barrierefreie Mitglieder bereit, die sie als Sequenz qualifizieren (§18.1); und
  • der Ausdruck E[0] gültig ist und denselben Indexer verwendet, der als Sequenz qualifiziert T ist

dann wird der Ausdruck E[A] implizit unterstützt.

Ohne anderweitige Einschränkung der Implementierungen dieses Standards entspricht die Bewertungsreihenfolge des Ausdrucks folgendem:

  1. E wird ausgewertet;
  2. A wird ausgewertet;
  3. die zählbare Eigenschaft ausgewertet T wird, sofern dies durch die Implementierung erforderlich ist;
  4. der Abrufen oder Festlegen des Accessors des int basierten Indexers T , von dem im gleichen Kontext verwendet E[0] wird, wird aufgerufen.

Unterstützung für impliziten Bereich 18.4.3

Wenn in irgendeinem Kontext ein element_access Ausdruck (§12.8.12) des Formulars E[A]; hat E Typ T und A ist ein einzelner Ausdruck implizit konvertierbar in Range; ist ungültig (§18.4.1), wenn in demselben Kontext:

  • T stellt barrierefreie Member bereit, die sie als zählbar und datenschnittfähig qualifizieren (§18.1)

dann wird der Ausdruck E[A] implizit unterstützt.

Ohne anderweitige Einschränkung der Implementierungen dieses Standards entspricht die Bewertungsreihenfolge des Ausdrucks folgendem:

  1. E wird ausgewertet;
  2. A wird ausgewertet;
  3. die zählbare Eigenschaft ausgewertet T wird, sofern dies durch die Implementierung erforderlich ist;
  4. die Slice Methode aufgerufen T wird.