Delen via


18 Uitgebreide indexering en segmentering

18.1 Algemeen

Deze component introduceert een model voor uitgebreide indexeerbare en sliceerbareverzamelingstypen die zijn gebouwd op:

  • De typen die in deze component zijn geïntroduceerd (System.Index§18.2) en System.Range (§18.3);
  • De vooraf gedefinieerde unaire ^ operators (§12.9.6) en binaire .. operatoren (§12.10) en
  • De element_access-expressie .

Onder het model wordt een type geclassificeerd als:

  • een verzameling als deze een groep elementenvertegenwoordigt
  • een uitgebreide indexeerbare verzameling als deze een element_access-expressie ondersteunt die één argumentexpressie van het type Index heeft die één element van het type retourneert en/of één element van het type instelt, hetzij op waarde of op verwijzing; en
  • een uitgebreide sliceerbare verzameling als deze een element_access-expressie ondersteunt die één argumentexpressie van het type Range heeft die een segment retourneert van de elementen van het type op waarde.

Opmerking: Voor het model is niet vereist dat een segment van het type kan worden ingesteld, maar een type kan dit ondersteunen als uitbreiding van het model. eindnotitie

Het model wordt ondersteund voor enkelvoudige matrices (§12.8.12.2) en tekenreeksen (§12.8.12.3).

Het model kan worden ondersteund door elk klasse-, struct- of interfacetype dat de juiste indexeerfuncties (§15.9) biedt die de semantiek van het model implementeren.

Impliciete ondersteuning voor het model wordt geboden voor typen die het niet rechtstreeks ondersteunen, maar die een bepaald patroon van leden bieden (§18.4). Deze ondersteuning is gebaseerd op patronen, in plaats van op semantisch, omdat de semantiek van het typeleden waarop deze is gebaseerd, wordt ervan uitgegaan dat de taal de semantiek van dit type leden niet afdwingt of controleert.

Voor de doeleinden van deze component worden de volgende voorwaarden gedefinieerd:

  • Een verzameling is een type dat een groep elementenvertegenwoordigt.
  • Een aftelbare verzameling is een verzameling die een aftelbare eigenschap een inteigenschap -valued instance biedt waarvan de waarde het aantal elementen is dat zich momenteel in de groep bevindt. Deze eigenschap krijgt de naam of LengthCount. De eerste wordt gekozen als beide bestaan.
  • Een reeks of indexeerbaar type is een verzameling:
    • dat kan worden geteld;
    • waar elk element kan worden geopend met behulp van een element_access-expressie met één vereist int argument, zijn de vanaf-start-index, aanvullende optionele argumenten toegestaan;
    • een reeks kan worden gewijzigd als elk element ook kan worden ingesteld met behulp van een element_access expressie;
    • De from-start-index van een element is het aantal elementen voordat dit in de reeks voorkomt, voor een reeks met N-elementen :
      • de eerste en laatste elementen bevatten indexen van respectievelijk 0 en N-1, en
      • de afgelopen-eindindex, een index die een hypothetisch element na het laatste element vertegenwoordigt, heeft de waarde N.
  • Een from-end-index vertegenwoordigt de positie van een element binnen een reeks ten opzichte van de afgelopen-endindex. Voor een reeks met N-elementen zijn de eerste, laatste en laatste indexen respectievelijk N, 1 en 0.
  • Een bereik is een aaneengesloten uitvoering van nul of meer indexen die beginnen bij een index binnen een reeks.
  • Een segment is de verzameling elementen binnen een bereik.
  • Een sliceerbare verzameling is een verzameling die:
    • is telbaar;
    • biedt een methode Slice die twee int parameters gebruikt die een bereik opgeven, een beginindex en een aantal elementen zijn en een nieuw segment retourneert dat is samengesteld uit de elementen in het bereik.

De bovenstaande definities worden uitgebreid voor gebruik van Index en Range als volgt:

  • Een type is ook een reeks als een element_access expressie die één vereist Index argument gebruikt in plaats van een int argument, wordt ondersteund. Als een onderscheid is vereist, wordt het type uitgebreid geïndexeerd.
  • Een type is ook segmenteerbaar als een element_access expressie die één vereist Range argument gebruikt, in plaats van een Slice methode, wordt ondersteund. Als een onderscheid is vereist, wordt het type uitgebreid gesegmenteerd.

Of een type is geclassificeerd als telbaar, indexeerbaar of segmenteerbaar is, is onderhevig aan de beperkingen van de toegankelijkheid van leden (§7.5) en is dus afhankelijk van waar het type wordt gebruikt.

Voorbeeld: Een type waarbij de betelbare eigenschap en/of de indexeerfunctie slechts een reeks is protected voor leden van zichzelf en eventuele afgeleide typen. eindvoorbeeld

De vereiste leden voor een type dat als een reeks of slicebaar kan worden aangemerkt, kunnen worden overgenomen.

Voorbeeld: In de volgende 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) { … }
}

Het type A kan worden geteld, B is een reeks en C is sliceerbaar en een reeks.

eindvoorbeeld

Opmerking:

  • Een type kan worden gesegmenteerd zonder indexeerbaar te zijn vanwege het ontbreken van een (toegankelijke) indexeerfunctie.
  • Als u een type wilt segmenteerbaar en/of indexeerbaar wilt maken, moet het type worden geteld.
  • Hoewel de elementen van een reeks worden geordend op positie binnen de reeks, hoeven de elementen zelf niet te worden geordend op hun waarde of zelfs op volgorde.

eindnotitie

18.2 Het indextype

Het System.Index type vertegenwoordigt een abstracte index die een beginindex of een from-end-index is.

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

Indexwaarden worden samengesteld op basis van een int, waarbij de niet-negatieve verschuiving wordt opgegeven en een bool, waarmee wordt aangegeven of de offset van het einde (true) of het begin () ligt.false Als de opgegeven offset negatief is, wordt er een ArgumentOutOfRangeException gegenereerd.

Voorbeeld

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

eindvoorbeeld

Er is een impliciete conversie van intIndex waaruit van beginindexen wordt geproduceerd en een door de taal gedefinieerde unaire operator ^ (§12.9.6) van intIndex waaruit van eindindexen wordt geproduceerd.

Voorbeeld

Het gebruik van impliciete conversies en de unaire ^ operator van de bovenstaande voorbeelden kan worden geschreven:

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

eindvoorbeeld

De methode GetOffset converteert van een abstracte Index waarde naar een concrete int indexwaarde voor een reeks van de opgegeven lengthwaarden. Als de Index waarde I, is van einde deze methode retourneert dezelfde waarde als length - I.Value, anders retourneert deze dezelfde waarde als I.Value.

Met deze methode wordt niet gecontroleerd of de retourwaarde zich in het geldige bereik van 0length-1 inclusief bevindt.

Notitie: Er wordt geen controle opgegeven als het verwachte gebruik van het resultaat is om te indexeren in een reeks met length elementen en dat indexeringsbewerking naar verwachting de juiste controles uitvoert. eindnotitie

Index IEquatable<Index> implementeert en waarden kunnen worden vergeleken voor gelijkheid op basis van de abstracte waarde; twee Index waarden zijn gelijk als en alleen als de respectieve Value en IsFromEnd eigenschappen gelijk zijn. Waarden worden echter Index niet geordende en er worden geen andere vergelijkingsbewerkingen verstrekt.

Notitie:Index waarden zijn niet gerangschikt omdat het abstracte indexen zijn, het is in het algemeen onmogelijk om te bepalen of een van-eindindex vóór of na een beginindex komt zonder verwijzing naar een reekslengte. Zodra de index is omgezet in concrete indexen, bijvoorbeeld door GetOffset, zijn die concrete indexen vergelijkbaar. eindnotitie

Index waarden kunnen rechtstreeks worden gebruikt in de argument_list van een element_access-expressie (§12.8.12), namelijk:

  • een matrixtoegang en het doel is een enkelvoudige matrix (§12.8.12.2);
  • een tekenreekstoegang (§12.8.12.3)
  • een indexeerfunctietoegang en het doeltype heeft een indexeerfunctie met bijbehorende parameters van beide Index typen (§12.8.12.4) of van een type waarvan Index de waarden impliciet worden omgezet; of
  • een indexeerfunctietoegang en het doeltype voldoet aan een reekspatroon waarvoor impliciete Index ondersteuning is opgegeven (§18.4.2).

18.3 Het bereiktype

Het System.Range type vertegenwoordigt het abstracte bereik van Indexes van een Start index tot, maar niet inclusief, een End index.

    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 waarden worden samengesteld uit twee Index waarden.

Voorbeeld

In de volgende voorbeelden wordt de impliciete conversie van int (Index§18.2) en de ^ operator (§12.9.6) gebruikt om de waarden voor elk van deze IndexRangewaarden te maken:

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`

eindvoorbeeld

De door de taal gedefinieerde operator .. (§12.10) maakt een Range waarde op basis van Index waarden.

Voorbeeld

Met behulp van de .. operator kunnen de bovenstaande voorbeelden worden geschreven:

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`

eindvoorbeeld

De operanden van .. zijn optioneel, de eerste standaard 0ingesteld op , de tweede standaardwaarde ^0.

Voorbeeld

Vijf van de bovenstaande voorbeelden kunnen worden ingekort door te vertrouwen op standaardwaarden voor operanden:

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`

eindvoorbeeld

Een Range waarde is geldig met betrekking tot een lengte L als:

  • de concrete indexen met betrekking tot L van de Range eigenschappen Start en End bevinden zich in het bereik van 0 tot L; en
  • de betonindex voor Start niet groter is dan de betonindex voor End

De methode GetOffsetAndLength met een argument length converteert een abstracte Range waarde naar een concrete Range waarde die wordt vertegenwoordigd door tuple. Als de methode Range niet geldig is ten opzichte length van de methode.ArgumentOutOfRangeException

De geretourneerde beton Range tuple is een paar van de vorm (S, N) waarbij:

  • S is het beginverschil van het bereik, de concrete index voor de eigenschap van de StartRange; en
  • N is het aantal items in het bereik, het verschil tussen de concrete indexen voor de End en Start eigenschappen;
  • beide waarden worden berekend met betrekking tot length.

Een concrete bereikwaarde is leeg als N nul is. Een leeg betonbereik kan een S waarde hebben die gelijk is aan de betonverloopindex (§18.1), een niet-leeg bereik mag dat niet zijn. Wanneer een Range verzameling die wordt gebruikt om te segmenteren (§18.1) een verzameling geldig en leeg is met betrekking tot die verzameling, is het resulterende segment een lege verzameling.

Notitie: Een gevolg van het bovenstaande is dat een Range waarde die geldig en leeg is met betrekking tot een length nul, kan worden gebruikt om een lege verzameling te segmenteren en resulteert in een leeg segment. Dit verschilt van indexering die een uitzondering genereert als de verzameling leeg is. eindnotitie*

Voorbeeld

De hierboven gedefinieerde variabelen gebruiken met 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 IEquatable<Range> implementeert en waarden kunnen worden vergeleken voor gelijkheid op basis van de abstracte waarde; twee Range waarden zijn gelijk als en alleen als de abstracte waarden van de respectieve Start en End eigenschappen gelijk zijn (§18.2). Waarden worden echter Range niet geordende en er worden geen andere vergelijkingsbewerkingen verstrekt.

Notitie:Range waarden zijn niet gerangschikt, zowel omdat ze abstract zijn en er geen unieke volgorderelatie is. Eenmaal omgezet in een concrete begin- en lengte, bijvoorbeeld door GetOffsetAndLength, kan een ordenenrelatie worden gedefinieerd. eindnotitie

Range waarden kunnen rechtstreeks worden gebruikt in de argument_list van een element_access-expressie (§12.8.12), namelijk:

  • een matrixtoegang en het doel is een enkelvoudige matrix (§12.8.12.2);
  • een tekenreekstoegang (§12.8.12.3);
  • een indexeerfunctietoegang en het doeltype heeft een indexeerfunctie met bijbehorende parameters van beide Range typen (§12.8.12.4) of van een type waarvan Range de waarden impliciet worden omgezet; of
  • een indexeerfunctietoegang (§12.8.12.4) en het doeltype voldoet aan een reekspatroon waarvoor impliciete Range ondersteuning is opgegeven (§18.4.3).

18.4 Impliciete ondersteuning op basis van patronen voor index en bereik

18.4.1 Algemeen

Als een element_access expressie (§12.8.12) van het formulier E[A]; waarbij E het type T heeft en A één expressie impliciet converteerbaar is naar Index of Range; niet kan worden geïdentificeerd als:

vervolgens wordt impliciete ondersteuning voor de expressie geboden als T deze voldoet aan een bepaald patroon. Als T dit patroon niet voldoet, treedt er een compilatietijdfout op.

18.4.2 Ondersteuning voor impliciete index

Als in een context een element_access expressie (§12.8.12) van het formulier E[A]; waarbij E het type T heeft en A één expressie impliciet converteerbaar is naar Index; niet geldig is (§18.4.1), dan als in dezelfde context:

  • T biedt toegankelijke leden die het kwalificeren als een reeks (§18.1); en
  • de expressie E[0] geldig is en dezelfde indexeerfunctie gebruikt die in aanmerking komt T als een reeks

vervolgens wordt de expressie E[A] impliciet ondersteund.

Zonder dat de uitvoeringen van deze standaard anders worden beperkt, is de volgorde van evaluatie van de expressie gelijk aan:

  1. E wordt geëvalueerd;
  2. A wordt geëvalueerd;
  3. de te tellen eigenschap van T wordt geëvalueerd, indien vereist door de implementatie;
  4. de get or set accessor van de int gebaseerde indexeerfunctie van T die wordt gebruikt E[0] in dezelfde context wordt aangeroepen.

18.4.3 Ondersteuning voor impliciet bereik

Als in een context een element_access expressie (§12.8.12) van het formulier E[A]; waarbij E het type T heeft en A één expressie impliciet converteerbaar is naar Range; niet geldig is (§18.4.1), dan als in dezelfde context:

  • T biedt toegankelijke leden die deze kwalificeren als zowel telbaar als slicebaar (§18.1)

vervolgens wordt de expressie E[A] impliciet ondersteund.

Zonder dat de uitvoeringen van deze standaard anders worden beperkt, is de volgorde van evaluatie van de expressie gelijk aan:

  1. E wordt geëvalueerd;
  2. A wordt geëvalueerd;
  3. de te tellen eigenschap van T wordt geëvalueerd, indien vereist door de implementatie;
  4. de Slice methode wordt T aangeroepen.