Dela via


18 Utökad indexering och segmentering

18.1 Allmänt

Den här satsen introducerar en modell för utökade indexerbara och utsnittsbarasamlingstyper som bygger på:

  • De typer som introduceras i denna sats(System.Index§18.2) och System.Range (§18.3);
  • De fördefinierade unary ^ -operatorerna (§12.9.6) och binära .. (§12.10) och
  • Uttrycket element_access .

Under modellen klassificeras en typ som:

  • en samling om den representerar en grupp med elements
  • en utökad indexerbar samling om den stöder ett element_access uttryck som har ett enda argumentuttryck av typen Index som returnerar och/eller anger ett enda element av typen, antingen efter värde eller referens, och
  • en utökad utsnittsbar samling om den stöder ett element_access uttryck som har ett enda argumentuttryck av typen Range som returnerar en sektor av elementen av typen efter värde.

Obs! Modellen kräver inte att en sektor av typen kan anges, men en typ kan ha stöd för den som en förlängning av modellen. slutkommentar

Modellen stöds för endimensionella matriser (§12.8.12.2) och strängar (§12.8.12.3).

Modellen kan stödjas av vilken klass, struct eller gränssnittstyp som helst som tillhandahåller lämpliga indexerare (§15.9) som implementerar modellsemantiken.

Implicit stöd för modellen tillhandahålls för typer som inte direkt stöder den men som ger ett visst mönster av medlemmar (§18.4). Det här stödet är mönsterbaserat snarare än semantiskt baserat, eftersom semantiken för de typmedlemmar som den baseras på antas – språket tillämpar inte, eller kontrollerar, semantiken för dessa typmedlemmar.

I den här satsen definieras följande termer:

  • En samling är en typ som representerar en grupp elements.
  • En countable-samling är en som ger en räknaregenskap en intvärdeinstansegenskap vars värde är antalet element som för närvarande finns i gruppen. Den här egenskapen ska ha namnet antingen Length eller Count. Den förra väljs om båda finns.
  • En sekvens eller indexerbar typ är en samling:
    • som kan räknas.
    • där varje element kan nås med hjälp av ett element_access uttryck med ett enda obligatoriskt int argument tillåts från-start-indexet, ytterligare valfria argument.
    • En sekvens kan ändras om varje element också kan anges med hjälp av ett element_access uttryck.
    • ett elements index från början är antalet element före det i sekvensen, för en sekvens som innehåller N-element :
      • de första och sista elementen har index på 0 respektive N-1 och
      • det tidigare indexet, ett index som representerar ett hypotetiskt element efter det sista, har värdet N.
  • Ett index från slutpunkt representerar ett elements position inom en sekvens i förhållande till det tidigare slutindexet. För en sekvens som innehåller N-element är de första, sista och tidigare slutindexen N, 1 respektive 0.
  • Ett intervall är en sammanhängande körning med noll eller fler index som börjar vid ett index i en sekvens.
  • Ett segment är en samling element inom ett intervall.
  • En utsnittsbar samling är en som:
    • kan räknas.
    • tillhandahåller en metod Slice som tar två int parametrar som anger ett intervall, som är ett startindex respektive ett antal element, och returnerar en ny sektor som konstruerats från elementen i intervallet.

Ovanstående definitioner utökas för användning av Index och Range enligt följande:

  • En typ är också en sekvens om ett element_access uttryck som tar ett enda obligatoriskt Index argument, i stället för ett int argument, stöds. Om en skillnad krävs kallas typen utökad indexerbar.
  • En typ är också utsnittsbar om ett element_access uttryck som tar ett enda obligatoriskt Range argument, i stället för en Slice metod, stöds. Om en skillnad krävs kallas typen utökad utsnittsbar.

Om en typ klassificeras som räknare, indexerbar eller utsnittsbar omfattas av begränsningarna för medlemstillgänglighet (§7.5) och därför beroende på var typen används.

Exempel: En typ där den countable egenskapen och/eller indexeraren är protected är bara en sekvens till medlemmar av sig själv och eventuella härledda typer. slutexempel

De medlemmar som krävs för att en typ ska kvalificeras som en sekvens eller utsnittsbar kan ärvas.

Exempel: I följande kod

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

Typen A kan räknas, B är en sekvens och C är utsnittsbar och en sekvens.

slutexempel

Note:

  • En typ kan vara utsnittsbar utan att vara indexerbar på grund av bristen på en (tillgänglig) indexerare.
  • För att en typ ska vara utsnittsbar och/eller indexerbar måste typen vara räknad.
  • Medan elementen i en sekvens sorteras efter position i sekvensen, behöver själva elementen inte sorteras efter deras värde eller ens ordnas.

slutkommentar

18.2 Indextypen

Typen System.Index representerar ett abstrakt index som antingen är ett index från början eller ett index från slutpunkt.

    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 värden skapas från en int, som anger den icke-negativa förskjutningen och en bool, som anger om förskjutningen kommer från slutet (true) eller start (false). Om den angivna förskjutningen är negativ utlöses en ArgumentOutOfRangeException .

Exempel

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

slutexempel

Det finns en implicit konvertering från int till Index vilken genererar index från början och en språkdefinierad unary-operator ^ (§12.9.6) från intIndex vilken genererar index från slutpunkt.

Exempel

Med implicita konverteringar och unary-operatorn ^ kan exemplen ovan skrivas:

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

slutexempel

Metoden GetOffset konverterar från ett abstrakt Index värde till ett konkret int indexvärde för en sekvens av den angivna length. Om värdet Index , Iär från slutet returnerar den här metoden samma värde som length - I.Value, annars returneras samma värde som I.Value.

Den här metoden kontrollerar inte att returvärdet är inom det giltiga intervallet 0 för genom length-1 inklusive.

Not: Ingen kontroll anges eftersom den förväntade användningen av resultatet är att indexera i en sekvens med length element och att indexeringsåtgärden förväntas utföra lämpliga kontroller. slutkommentar

Index implementeringar IEquatable<Index> och värden kan jämföras för likhet baserat på det abstrakta värdet. Två Index värden är lika om och endast om respektive Value och IsFromEnd egenskaper är lika. Värden ordnas dock Index inte och inga andra jämförelseåtgärder tillhandahålls.

Not:Index värden är osorterade eftersom de är abstrakta index, är det i allmänhet omöjligt att avgöra om ett frånslutsindex kommer före eller efter ett från startindex utan referens till en sekvenslängd. När de har konverterats till konkreta index, t.ex. av GetOffset, är de konkreta indexen jämförbara. slutkommentar

Index värden kan användas direkt i argument_list av ett element_access uttryck (§12.8.12) som är:

  • en matrisåtkomst och målet är en endimensionell matris (§12.8.12.2);
  • a string access (§12.8.12.3)
  • en indexerares åtkomst och måltypen har en indexerare med motsvarande parametrar av antingen Index typ (§12.8.12.4) eller av en typ som Index värden implicit kan konverteras till, eller
  • en indexerares åtkomst och måltypen överensstämmer med ett sekvensmönster för vilket implicit Index stöd anges (§18.4.2).

18.3 Områdestypen

Typen System.Range representerar det abstrakta intervallet av Indexes från ett Start index upp till, men inte inklusive, ett 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 värden konstrueras från två Index värden.

Exempel

I följande exempel används implicit konvertering från int till Index (§18.2) och operatorn ^ (§12.9.6) för att skapa Index värdena för varje 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`

slutexempel

Den språkdefinierade operatorn .. (§12.10) skapar ett Range värde från Index värden.

Exempel

Med operatorn .. ovan kan exemplen ovan skrivas:

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`

slutexempel

Operanderna .. i är valfria, det första standardvärdet är 0, det andra standardvärdet är ^0.

Exempel

Fem av exemplen ovan kan förkortas genom att förlita sig på standardvärden för operander:

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`

slutexempel

Ett Range värde är giltigt med avseende på en längd L om:

  • de konkreta indexen avseende L av Range egenskaperna Start och End ligger i intervallet 0 till L;
  • betongindexet för Start är inte större än det konkreta indexet för End

Metoden GetOffsetAndLength med ett argument length konverterar ett abstrakt Range värde till ett konkret Range värde som representeras av tuppeln. Range Om är ogiltigt med avseende length på metoden genererar ArgumentOutOfRangeException.

Den returnerade betongtuppeln Range är ett par av formen (S, N) där:

  • Sär startförskjutningen för intervallet, som är det konkreta indexet för egenskapen Startför Range ; och
  • N är antalet objekt i intervallet, vilket är skillnaden mellan de konkreta indexen End för egenskaperna och Start ;
  • båda värdena beräknas med avseende lengthpå .

Ett värde för betongintervall är tomt om N det är noll. Ett tomt betongområde kan ha ett S värde som är lika med betongindex (§18.1), ett icke-tomt intervall får inte. När en Range som används för att segmentera (§18.1) är en samling giltig och tom med avseende på den samlingen är den resulterande sektorn en tom samling.

Not: En följd av ovanstående är att ett Range värde som är giltigt och tomt med avseende på noll length kan användas för att segmentera en tom samling och resultera i en tom sektor. Detta skiljer sig från indexering som genererar ett undantag om samlingen är tom. slutkommentar*

Exempel

Använd variablerna som definierats ovan med 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 implementeringar IEquatable<Range> och värden kan jämföras för likhet baserat på det abstrakta värdet. Två Range värden är lika om och endast om de abstrakta värdena för respektive Start och End egenskaperna är lika (§18.2). Värden ordnas dock Range inte och inga andra jämförelseåtgärder tillhandahålls.

Not:Range värdena är osorterade eftersom de är abstrakta och det inte finns någon unik ordningsrelation. När den har konverterats till en konkret start och längd, t.ex. av GetOffsetAndLength, kan en orderrelation definieras. slutkommentar

Range värden kan användas direkt i argument_list av ett element_access uttryck (§12.8.12) som är:

  • en matrisåtkomst och målet är en endimensionell matris (§12.8.12.2);
  • en strängåtkomst (§12.8.12.3);
  • en indexerares åtkomst och måltypen har en indexerare med motsvarande parametrar av antingen Range typ (§12.8.12.4) eller av en typ som Range värden implicit kan konverteras till, eller
  • en indexerare (§12.8.12.4) och måltypen överensstämmer med ett sekvensmönster som implicit Range stöd anges för (§18.4.3).

18.4 Mönsterbaserat implicit stöd för index och intervall

18.4.1 Allmänt

Om ett element_access uttryck (§12.8.12) i formuläret E[A], där E har typ T och A är ett enda uttryck implicit konvertibelt till Index eller Range; inte kan identifieras som:

sedan tillhandahålls implicit stöd för uttrycket om T det överensstämmer med ett visst mönster. Om T inte överensstämmer med det här mönstret uppstår ett kompileringsfel.

Stöd för implicit index 18.4.2

Om i något sammanhang ett element_access uttryck (§12.8.12) av formuläret E[A]; där E har typ T och A är ett enda uttryck implicit konvertibelt till Index; är inte giltigt (§18.4.1) om i samma sammanhang:

  • T ger tillgängliga medlemmar som kvalificerar det som en sekvens (§18.1); och
  • uttrycket E[0] är giltigt och använder samma indexerare som kvalificerar T sig som en sekvens

ska uttrycket E[A] underförstått stödjas.

Utan att i övrigt begränsa genomförandet av denna standard skall utvärderingsordningen för uttrycket motsvara följande:

  1. E utvärderas.
  2. A utvärderas.
  3. Den antalsbara egenskapen T för utvärderas, om det krävs av implementeringen.
  4. get- eller set-åtkomstorn för den int baserade indexeraren T för som skulle användas av E[0] i samma kontext anropas.

Stöd för implicit intervall 18.4.3

Om i något sammanhang ett element_access uttryck (§12.8.12) av formuläret E[A]; där E har typ T och A är ett enda uttryck implicit konvertibelt till Range; är inte giltigt (§18.4.1) om i samma sammanhang:

  • T tillhandahåller tillgängliga medlemmar som kvalificerar den som både räknare ochutsnittsbar (§18.1)

ska uttrycket E[A] underförstått stödjas.

Utan att i övrigt begränsa genomförandet av denna standard skall utvärderingsordningen för uttrycket motsvara följande:

  1. E utvärderas.
  2. A utvärderas.
  3. Den antalsbara egenskapen T för utvärderas, om det krävs av implementeringen.
  4. - Slice metoden T anropas.