Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
18.1 General
Esta cláusula presenta un modelo para los tipos de colecciónindexables y segmentables extendidos basados en:
- Los tipos introducidos en esta cláusula (
System.Index§18.2) ySystem.Range(§18.3); - Operadores unarios
^predefinidos (§12.9.6) y binarios..(§12.10); y - Expresión element_access .
En el modelo, un tipo se clasifica como:
- una colección si representa un grupo de elementos
- una colección indizable extendida si admite una expresión de element_access que tiene una expresión de argumento único de tipo
Indexque devuelve o establece un único elemento del tipo, ya sea por valor o por referencia; y - una colección segmentable extendida si admite una expresión element_access que tiene una expresión de argumento único de tipo
Rangeque devuelve un segmento de los elementos del tipo por valor.
Nota: El modelo no requiere que se pueda establecer un segmento del tipo, pero un tipo puede admitirlo como una extensión del modelo. nota final
El modelo se admite para matrices unidimensionales (§12.8.12.2) y cadenas (§12.8.12.3).
El modelo puede ser compatible con cualquier clase, estructura o tipo de interfaz que proporcione indizadores adecuados (§15.9) que implementen la semántica del modelo.
Se proporciona compatibilidad implícita para el modelo para los tipos que no lo admiten directamente, pero que proporcionan un determinado patrón de miembros (§18.4). Esta compatibilidad se basa en patrones, en lugar de en semántica, ya que se asume la semántica de los miembros de tipo en los que se basa: el lenguaje no aplica ni comprueba la semántica de estos miembros de tipo.
Para los fines de esta cláusula se definen los siguientes términos:
- Una colección es un tipo que representa un grupo de elementoss.
- Una colección con recuento es una que proporciona una propiedad countable una
intpropiedad de instancia con valores cuyo valor es el número de elementos que se encuentran actualmente en el grupo. Esta propiedad se denominará oLengthCount. El primero se elige si ambos existen. - Un tipo indizable o secuencia es una colección:
- que es countable;
- donde se puede tener acceso a cada elemento mediante una expresión element_access con un único argumento requerido
int, se permiten los argumentos opcionales adicionales del índice desde el inicio; - una secuencia es modificable si todos los elementos también se pueden establecer mediante una expresión element_access ;
- El índice de inicio de un elemento es el número de elementos antes que en la secuencia, para una secuencia que contiene N elementos:
- los primeros y últimos elementos tienen índices de 0 y N-1 respectivamente, y
- el índice de extremo anterior, un índice que representa un elemento hipotético después del último, tiene el valor N.
- Un índice de un extremo representa la posición de un elemento dentro de una secuencia relativa al índice de extremo anterior. Para una secuencia que contiene N elementos, los índices de primer, último y final son N, 1 y 0 respectivamente.
- Un intervalo es una ejecución contigua de cero o más índices a partir de cualquier índice dentro de una secuencia.
- Un segmento es la colección de elementos dentro de un intervalo.
- Una colección segmentable es una que:
- es countable;
- proporciona un método
Sliceque toma dosintparámetros que especifican un intervalo, siendo un índice inicial y un recuento de elementos respectivamente, y devuelve un nuevo segmento construido a partir de los elementos del intervalo.
Las definiciones anteriores se extienden para usos de Index y Range de la manera siguiente:
- Un tipo también es una secuencia si se admite una expresión element_access que toma un único argumento necesario
Index, en lugar de unintargumento. Cuando se requiere una distinción, el tipo se denomina indexable extendido. - Un tipo también se puede segmentar si se admite una expresión element_access que toma un único argumento necesario
Range, en lugar de unSlicemétodo. Cuando se requiere una distinción, el tipo se denomina segmentable extendido.
Si un tipo se clasifica como countable, indexable o segmentable está sujeto a las restricciones de accesibilidad de miembros (§7.5) y, por tanto, depende de dónde se use el tipo.
Ejemplo: un tipo en el que la propiedad countable o el indexador son
protectedsolo una secuencia para los miembros de sí mismos y cualquier tipo derivado. ejemplo final
Los miembros necesarios para que un tipo se califique como una secuencia o segmentación se pueden heredar.
Ejemplo: en el código siguiente
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) { … } }El tipo
Aes countable,Bes una secuencia yCse puede segmentar y una secuencia.ejemplo final
Nota:
- Un tipo se puede segmentar sin ser indexable debido a la falta de un indexador (accesible).
- Para que un tipo sea segmentable o indizable, es necesario contar el tipo.
- Aunque los elementos de una secuencia se ordenan por posición dentro de la secuencia, los propios elementos no deben ordenarse por su valor ni siquiera ordenarlos.
nota final
18.2 El tipo de índice
El System.Index tipo representa un índice abstracto que representa un índice desde el inicio o un índice desde el final.
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 los valores se construyen a partir de , intespecificando el desplazamiento no negativo y un bool, que indica si el desplazamiento es desde el final (true) o el inicio (false). Si el desplazamiento especificado es negativo, se produce una ArgumentOutOfRangeException excepción .
Ejemplo
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 ArgumentOutOfRangeExceptionejemplo final
Hay una conversión implícita de a int la Index que genera índices de inicio y un operador ^ unario definido por el lenguaje (§12.9.6) desde el int que genera índices desde Index el final.
Ejemplo
Con conversiones implícitas y el operador unario
^se pueden escribir los ejemplos anteriores:Index first = 0; // first element index var last = ^1; // last element index var past = ^0; // past-end indexejemplo final
El método GetOffset convierte de un valor abstracto Index a un valor de índice concreto int para una secuencia del especificado length. Si el Index valor , Ies del extremo , este método devuelve el mismo valor length - I.Valueque , de lo contrario, devuelve el mismo valor que I.Value.
Este método no comprueba que el valor devuelto está en el intervalo válido de a través 0 de length-1 inclusive.
Nota: No se especifica ninguna comprobación, ya que el uso esperado del resultado es indexar en una secuencia con
lengthelementos y se espera que la operación de indexación realice las comprobaciones adecuadas. nota final
Indeximplementaciones y valores se pueden comparar para la igualdad en función del valor abstracto; dos IEquatable<Index> valores son iguales Index si y solo si las propiedades y Value respectivas IsFromEnd son iguales. Sin embargo Index , no se ordenan los valores y no se proporciona ninguna otra operación de comparación.
Nota:
IndexLos valores no están ordenados, ya que son índices abstractos, es en general imposible determinar si un índice desde el extremo viene antes o después de un índice de inicio sin referencia a una longitud de secuencia. Una vez convertidos en índices concretos, por ejemplo, porGetOffset, esos índices concretos son comparables. nota final
Index Los valores se pueden usar directamente en el argument_list de una expresión de element_access (§12.8.12), que es:
- un acceso de matriz y el destino es una matriz unidimensional (§12.8.12.2);
- acceso a cadenas (§12.8.12.3)
- un acceso de indexador y el tipo de destino tiene un indexador con los parámetros correspondientes de cualquier
Indextipo (§12.8.12.4) o de un tipo al queIndexse pueden convertir implícitamente los valores; o - un acceso de indexador y el tipo de destino se ajusta a un patrón de secuencia para el que se especifica compatibilidad implícita
Index(§18.4.2).
18.3 El tipo de rango
El System.Range tipo representa el intervalo abstracto de es de Indexun Start índice hasta, pero no incluido, un End índice.
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 los valores se construyen a partir de dos Index valores.
Ejemplo
En los ejemplos siguientes se usa la conversión implícita de
intaIndex(§18.2) y el^operador (§12.9.6) para crear losIndexvalores para cadaRange: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`ejemplo final
El operador .. definido por el lenguaje (§12.10) crea un Range valor a partir de Index valores.
Ejemplo
Con el operador se pueden escribir los
..ejemplos anteriores: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`ejemplo final
Los operandos de .. son opcionales 0, el primer valor predeterminado es , el segundo valor predeterminado es ^0.
Ejemplo
Se pueden acortar cinco de los ejemplos anteriores si se basan en valores predeterminados para operandos:
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`ejemplo final
Un Range valor es válido con respecto a una longitud L si:
- los índices concretos con respecto a L de las
RangepropiedadesStartyEndestán en el intervalo de 0 a L; y - el índice concreto de
Startno es mayor que el índice concreto paraEnd
El método GetOffsetAndLength con un argumento length convierte un valor abstracto Range en un valor concreto Range representado por tupla. Si el objeto Range no es válido con respecto al length método produce ArgumentOutOfRangeException.
La tupla de hormigón Range devuelta es un par de la forma (S, N) donde:
-
Ses el desplazamiento inicial del intervalo, siendo el índice concreto para laStartpropiedad deRange; y -
Nes el número de elementos del rango, siendo la diferencia entre los índices concretos de lasEndpropiedades yStart; - ambos valores que se calculan con respecto a
length.
Un valor de intervalo concreto está vacío si N es cero. Un intervalo de hormigón vacío puede tener un S valor igual al índice de extremo pasado concreto (§18.1), es posible que un intervalo no vacío no sea vacío.
Range Cuando se usa para segmentar (§18.1), una colección es válida y está vacía con respecto a esa colección, el segmento resultante es una colección vacía.
Nota: Una consecuencia de lo anterior es que un
Rangevalor válido y vacío con respecto a unlengthde cero se puede usar para segmentar una colección vacía y da como resultado un segmento vacío. Esto difiere de la indexación que produce una excepción si la colección está vacía. nota final*
Ejemplo
Uso de las variables definidas anteriormente con
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
Rangeimplementaciones y valores se pueden comparar para la igualdad en función del valor abstracto; dos IEquatable<Range> valores son iguales si y solo si los valores abstractos Range de las propiedades respectivas Start y End son iguales (§18.2). Sin embargo Range , no se ordenan los valores y no se proporciona ninguna otra operación de comparación.
Nota:
Rangelos valores no están ordenados, ya que son abstractos y no hay ninguna relación de ordenación única. Una vez convertido en un inicio y una longitud concretos, por ejemplo, porGetOffsetAndLength, se podría definir una relación de ordenación. nota final
Range Los valores se pueden usar directamente en el argument_list de una expresión de element_access (§12.8.12), que es:
- un acceso de matriz y el destino es una matriz unidimensional (§12.8.12.2);
- acceso a cadenas (§12.8.12.3);
- un acceso de indexador y el tipo de destino tiene un indexador con los parámetros correspondientes de cualquier
Rangetipo (§12.8.12.4) o de un tipo al queRangese pueden convertir implícitamente los valores; o - un acceso de indexador (§12.8.12.4) y el tipo de destino se ajusta a un patrón de secuencia para el que se especifica compatibilidad implícita
Range(§18.4.3).
18.4 Compatibilidad implícita basada en patrones para Index y Range
18.4.1 General
Si una expresión element_access (§12.8.12) del formulario E[A]; donde E tiene el tipo T y A es una expresión única que se puede convertir implícitamente en Index o Range; no se puede identificar como:
- acceso a una matriz (§12.8.12.2),
- acceso a cadenas (§12.8.12.3) o
- un acceso al indexador (§12.8.12.4), ya
Tque no proporciona ningún indexador accesible adecuado
a continuación, se proporciona compatibilidad implícita con la expresión si T se ajusta a un patrón determinado. Si T no se ajusta a este patrón, se produce un error en tiempo de compilación.
Compatibilidad con índices implícitos 18.4.2
Si en cualquier contexto, una expresión element_access (§12.8.12) del formulario E[A]; donde E tiene el tipo T y A es una expresión única que se puede convertir implícitamente en Index; no es válida (§18.4.1), si está en el mismo contexto:
-
Tproporciona a los miembros accesibles que lo califican como una secuencia (§18.1); y - la expresión
E[0]es válida y usa el mismo indexador que seTcalifica como una secuencia.
después, la expresión E[A] se admitirá implícitamente.
Sin restringir de otra manera las implementaciones de este estándar, el orden de evaluación de la expresión será equivalente a:
-
Ese evalúa; -
Ase evalúa; - Se evalúa la propiedad de recuento de
T, si es necesario por la implementación; - Se invoca el descriptor de acceso get o set del
intindexador basado deTque usaríaE[0]en el mismo contexto.
Compatibilidad con intervalos implícitos 18.4.3
Si en cualquier contexto, una expresión element_access (§12.8.12) del formulario E[A]; donde E tiene el tipo T y A es una expresión única que se puede convertir implícitamente en Range; no es válida (§18.4.1), si está en el mismo contexto:
-
Tproporciona a los miembros accesibles que lo califican como recuentos y segmentables (§18.1)
después, la expresión E[A] se admitirá implícitamente.
Sin restringir de otra manera las implementaciones de este estándar, el orden de evaluación de la expresión será equivalente a:
-
Ese evalúa; -
Ase evalúa; - Se evalúa la propiedad de recuento de
T, si es necesario por la implementación; - se invoca el
Slicemétodo deT.
ECMA C# draft specification