Partager via


18 Indexation et découpage étendus

18.1 Général

Cette clause introduit un modèle pour les types de collectionindexables et segmentables étendus basés sur :

  • Types introduits dans cette clause, System.Index (§18.2) et System.Range (§18.3) ;
  • Opérateurs unaires prédéfinis ^ (§12.9.6) et binaires .. (§12.10) et
  • Expression element_access .

Sous le modèle, un type est classé comme suit :

  • une collection si elle représente un groupe d’élémentss
  • collection indexable étendue si elle prend en charge une expression element_access qui a une expression d’argument unique de type Index qui retourne et/ou définit un élément unique du type, par valeur ou par référence ;
  • collection segmentable étendue si elle prend en charge une expression element_access qui a une expression d’argument unique de type Range qui retourne une tranche des éléments du type par valeur.

Remarque : le modèle ne nécessite pas qu’une tranche du type puisse être définie, mais un type peut le prendre en charge en tant qu’extension du modèle. fin de la remarque

Le modèle est pris en charge pour les tableaux unidimensionnels (§12.8.12.2) et les chaînes (§12.8.12.3).

Le modèle peut être pris en charge par n’importe quelle classe, struct ou type d’interface qui fournit des indexeurs appropriés (§15.9) qui implémentent la sémantique du modèle.

La prise en charge implicite du modèle est fournie pour les types qui ne le prennent pas directement en charge, mais qui fournissent un certain modèle de membres (§18.4). Cette prise en charge est basée sur des modèles plutôt que sur la sémantique, car la sémantique des membres de type sur lequel elle est basée est supposée : le langage n’applique pas, ni vérifie, la sémantique de ces membres de type.

Pour les besoins de cette clause, les termes suivants sont définis :

  • Une collection est un type qui représente un groupe d’éléments.
  • Une collection countable est une collection qui fournit une propriété countable une propriété d’instance int-valued dont la valeur est le nombre d’éléments actuellement dans le groupe. Cette propriété doit être nommée soit LengthCount. L’ancien est choisi s’il existe les deux.
  • Une séquence ou un type indexable est une collection :
    • qui est countable ;
    • où chaque élément est accessible à l’aide d’une expression element_access avec un seul argument obligatoire int , l’index de départ, d’autres arguments facultatifs sont autorisés ;
    • une séquence est modifiable si chaque élément peut également être défini à l’aide d’une expression element_access  ;
    • L’index de début d’un élément est le nombre d’éléments avant celui-ci dans la séquence, pour une séquence contenant des éléments N :
      • les premiers et derniers éléments ont respectivement des indices de 0 et N-1, et
      • l’index passé, un index qui représente un élément hypothétique après le dernier, a la valeur N.
  • Un index de bout représente la position d’un élément dans une séquence par rapport à l’index passé. Pour une séquence contenant des éléments N , les index de dernière et dernière fin sont respectivement N, 1 et 0.
  • Une plage est une exécution contiguë de zéro ou plusieurs index commençant à n’importe quel index dans une séquence.
  • Une tranche est la collection d’éléments dans une plage.
  • Une collection segmentable est une collection qui :
    • est countable ;
    • fournit une méthode Slice qui accepte deux int paramètres spécifiant une plage, étant un index de départ et un nombre d’éléments respectivement, et retourne une nouvelle tranche construite à partir des éléments de la plage.

Les définitions ci-dessus sont étendues pour les utilisations et IndexRange comme suit :

  • Un type est également une séquence si une expression element_access prenant un seul argument obligatoire Index , plutôt qu’un int argument, est prise en charge. Lorsqu’une distinction est requise, le type est appelé indexable étendu.
  • Un type est également segmentable si une expression element_access prenant un seul argument obligatoire Range , plutôt qu’une Slice méthode, est prise en charge. Lorsqu’une distinction est requise, le type est appelé segment étendu.

Si un type est classé comme pouvant être comptabilisé, indexable ou segmentable est soumis aux contraintes d’accessibilité des membres (§7.5) et dépend donc de l’emplacement où le type est utilisé.

Exemple : type où la propriété countable et/ou l’indexeur ne sont protected qu’une séquence de membres de lui-même et de tous les types dérivés. fin d'exemple

Les membres requis pour un type à qualifier comme séquence ou segmentable peuvent être hérités.

Exemple : dans le code suivant

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

Le type A est countable, B est une séquence et C est segmentable et une séquence.

fin d'exemple

Remarque :

  • Un type peut être segmentable sans être indexable en raison de l’absence d’indexeur (accessible).
  • Pour qu’un type soit segmentable et/ou indexable, le type doit être countable.
  • Bien que les éléments d’une séquence soient classés par position dans la séquence, les éléments eux-mêmes n’ont pas besoin d’être classés par leur valeur, ou même ordonnés.

fin de la remarque

18.2 Type d’index

Le System.Index type représente un index abstrait qui représente un index de départ ou un index de bout en bout.

    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 les valeurs sont construites à partir d’un int, en spécifiant le décalage non négatif et en boolindiquant si le décalage est de la fin (true) ou du début (false). Si le décalage spécifié est négatif, il ArgumentOutOfRangeException est levée.

Exemple

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

fin d'exemple

Il existe une conversion implicite à int partir de Index laquelle produit des index de départ et un opérateur ^ unaire défini par le langage (§12.9.6) à int partir duquel Index produit des index de bout en bout.

Exemple

L’utilisation de conversions implicites et l’opérateur unaire ^ , les exemples ci-dessus peuvent être écrits :

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

fin d'exemple

La méthode GetOffset convertit d’une valeur abstraite Index en valeur d’index concrète int pour une séquence du fichier spécifié length. Si la Index valeur, est de bout en bout, Icette méthode retourne la même valeur que length - I.Value, sinon elle retourne la même valeur que I.Value.

Cette méthode ne vérifie pas que la valeur de retour se trouve dans la plage valide de 0 l’inclusion length-1 .

Note: Aucune vérification n’est spécifiée, car l’utilisation attendue du résultat consiste à indexer dans une séquence avec length des éléments, et que l’opération d’indexation est censée effectuer les vérifications appropriées. fin de la remarque

Indexles implémentations et les valeurs peuvent être comparées pour l’égalité en fonction de la valeur abstraite ; deux IEquatable<Index> valeurs sont égales Index si et seulement si les propriétés respectives et Value les IsFromEnd propriétés sont égales. Toutefois, Index les valeurs ne sont pas ordonnées et aucune autre opération de comparaison n’est fournie.

Note:Index les valeurs ne sont pas triées, car elles sont des index abstraits, il est en général impossible de déterminer si un index de bout en bout arrive avant ou après un index de début sans référence à une longueur de séquence. Une fois convertis en indices concrets, par exemple par GetOffset, ces indices de béton sont comparables. fin de la remarque

Index les valeurs peuvent être utilisées directement dans le argument_list d’une expression element_access (§12.8.12) qui est :

  • un accès au tableau et la cible est un tableau unidimensionnel (§12.8.12.2) ;
  • un accès de chaîne (§12.8.12.3)
  • un accès indexeur et le type cible possède un indexeur avec des paramètres correspondants de type Index (§12.8.12.4) ou d’un type vers lequel Index les valeurs sont implicitement convertibles ; ou
  • un accès d’indexeur et le type cible sont conformes à un modèle de séquence pour lequel la prise en charge implicite Index est spécifiée (§18.4.2).

18.3 Type de plage

Le System.Range type représente la plage abstraite d’es Indexd’un index jusqu’à un Start index, mais pas inclus, un 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 les valeurs sont construites à partir de deux Index valeurs.

Exemple

Les exemples suivants utilisent la conversion implicite de int vers Index (§18.2) et l’opérateur ^ (§12.9.6) pour créer les Index valeurs pour chaque 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`

fin d'exemple

L’opérateur .. défini par le langage (§12.10) crée une Range valeur à partir de Index valeurs.

Exemple

L’utilisation de l’opérateur .. ci-dessus peut être écrite :

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`

fin d'exemple

Les opérandes d’opérandes .. sont facultatifs 0, les premiers valeurs par défaut , la deuxième valeur par défaut ^0.

Exemple

Cinq des exemples ci-dessus peuvent être raccourcis en s’appuyant sur des valeurs par défaut pour les opérandes :

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`

fin d'exemple

Une Range valeur est valide par rapport à une longueur L si :

  • les indices concrets par rapport à L des Range propriétés Start et End se trouvent dans la plage de 0 à L ; et
  • l’index concret pour Start n’est pas supérieur à l’index concret pour End

La méthode GetOffsetAndLength avec un argument length convertit une valeur abstraite Range en une valeur concrète Range représentée par tuple. Si la Range valeur n’est pas valide par rapport à length la méthode lève ArgumentOutOfRangeException.

Le tuple béton Range retourné est une paire de la forme (S, N) où :

  • S est le décalage de départ de la plage, étant l’index concret pour la Start propriété du Range; et
  • Nest le nombre d’éléments de la plage, étant la différence entre les indices concrets pour les propriétés et End les Start propriétés ;
  • les deux valeurs calculées par rapport à length.

Une valeur de plage concrète est vide si N elle est égale à zéro. Une plage de béton vide peut avoir une S valeur égale à l’index final concret (§18.1), une plage non vide peut ne pas être vide. Lorsqu’une Range collection est utilisée pour trancher (§18.1) une collection est valide et vide par rapport à cette collection, alors la tranche résultante est une collection vide.

Note: Une conséquence du code ci-dessus est qu’une Range valeur valide et vide par rapport à un length zéro peut être utilisée pour découper une collection vide et entraîner une tranche vide. Cela diffère de l’indexation qui lève une exception si la collection est vide. Note de fin*

Exemple

Utilisation des variables définies ci-dessus avec 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

Rangeles implémentations et les valeurs peuvent être comparées pour l’égalité en fonction de la valeur abstraite ; deux IEquatable<Range> valeurs sont égales si et seulement si les valeurs abstraites Range des propriétés respectives Start sont End égales (§18.2). Toutefois, Range les valeurs ne sont pas ordonnées et aucune autre opération de comparaison n’est fournie.

Note:Range les valeurs ne sont pas triées, car elles sont abstraites et il n’existe aucune relation d’ordre unique. Une fois converti en début et longueur concrètes, par exemple, GetOffsetAndLengthune relation de classement peut être définie. fin de la remarque

Range les valeurs peuvent être utilisées directement dans la argument_list d’une expression element_access (§12.8.12) qui est :

  • un accès au tableau et la cible est un tableau unidimensionnel (§12.8.12.2) ;
  • un accès de chaîne (§12.8.12.3) ;
  • un accès indexeur et le type cible possède un indexeur avec des paramètres correspondants de type Range (§12.8.12.4) ou d’un type vers lequel Range les valeurs sont implicitement convertibles ; ou
  • un accès indexeur (§12.8.12.4) et le type cible sont conformes à un modèle de séquence pour lequel la prise implicite Range est spécifiée (§18.4.3).

Prise en charge implicite basée sur les modèles 18.4 pour l’index et la plage

18.4.1 Général

Si une expression element_access (§12.8.12) du formulaire E[A]; où E a le type T et A est une expression implicitement convertible en Index ou Range; ne peut pas être identifiée comme suit :

  • un accès au tableau (§12.8.12.2),
  • un accès de chaîne (§12.8.12.3) ou
  • un accès d’indexeur (§12.8.12.4) tel qu’il T ne fournit aucun indexeur accessible approprié

la prise en charge implicite de l’expression est fournie si T elle est conforme à un modèle particulier. Si T elle n’est pas conforme à ce modèle, une erreur au moment de la compilation se produit.

Prise en charge de l’index implicite 18.4.2

Si, dans un contexte quelconque, une expression element_access (§12.8.12) de la forme E[A]; où E a le type T et A est une expression unique implicitement convertible Indexen ; n’est pas valide (§18.4.1), si dans le même contexte :

  • Tfournit des membres accessibles qui le qualifient comme séquence (§18.1) ; et
  • l’expression E[0] est valide et utilise le même indexeur qu’une T séquence

l’expression E[A] est alors implicitement prise en charge.

Sans restreindre les implémentations de cette Norme, l’ordre d’évaluation de l’expression doit être équivalent à :

  1. E est évalué ;
  2. A est évalué ;
  3. la propriété countable d’est T évaluée, si nécessaire par l’implémentation ;
  4. l’accesseur get ou set de l’indexeur int de base utilisé T dans E[0] le même contexte est appelé.

Prise en charge de la plage implicite 18.4.3

Si, dans un contexte quelconque, une expression element_access (§12.8.12) de la forme E[A]; où E a le type T et A est une expression unique implicitement convertible Rangeen ; n’est pas valide (§18.4.1), si dans le même contexte :

  • T fournit des membres accessibles qui le qualifient à la fois comme pouvant être comptabilisés et segmentables (§18.1)

l’expression E[A] est alors implicitement prise en charge.

Sans restreindre les implémentations de cette Norme, l’ordre d’évaluation de l’expression doit être équivalent à :

  1. E est évalué ;
  2. A est évalué ;
  3. la propriété countable d’est T évaluée, si nécessaire par l’implémentation ;
  4. méthode Slice d’appel T .