IntervalosRanges
ResumenSummary
Esta característica trata sobre la entrega de dos nuevos operadores que permiten la construcción de objetos y , y su uso para indexar o segmentar System.Index System.Range colecciones en tiempo de ejecución.This feature is about delivering two new operators that allow constructing System.Index and System.Range objects, and using them to index/slice collections at runtime.
Información generalOverview
Tipos y miembros conocidosWell-known types and members
Para usar los nuevos formularios sintácticos para y , pueden ser necesarios nuevos tipos y miembros conocidos, en función de qué formularios System.Index System.Range sintácticos se usen.To use the new syntactic forms for System.Index and System.Range, new well-known types and members may be necessary, depending on which syntactic forms are used.
Para usar el operador "hat" ( ^ ), se requiere lo siguienteTo use the "hat" operator (^), the following is required
namespace System
{
public readonly struct Index
{
public Index(int value, bool fromEnd);
}
}
Para usar el System.Index tipo como argumento en un acceso de elemento de matriz, se requiere el siguiente miembro:To use the System.Index type as an argument in an array element access, the following member is required:
int System.Index.GetOffset(int length);
La .. System.Range sintaxis de requerirá el System.Range tipo , así como uno o varios de los miembros siguientes:The .. syntax for System.Range will require the System.Range type, as well as one or more of the following members:
namespace System
{
public readonly struct Range
{
public Range(System.Index start, System.Index end);
public static Range StartAt(System.Index start);
public static Range EndAt(System.Index end);
public static Range All { get; }
}
}
La .. sintaxis permite que no falte ninguno de sus argumentos.The .. syntax allows for either, both, or none of its arguments to be absent. Independientemente del número de argumentos, el Range constructor siempre es suficiente para usar la Range sintaxis .Regardless of the number of arguments, the Range constructor is always sufficient for using the Range syntax. Sin embargo, si alguno de los demás miembros está presente y falta uno o varios de los argumentos, se puede sustituir .. el miembro adecuado.However, if any of the other members are present and one or more of the .. arguments are missing, the appropriate member may be substituted.
Por último, para que un valor de tipo se utilice en una expresión de acceso de elemento de matriz, debe estar presente System.Range el siguiente miembro:Finally, for a value of type System.Range to be used in an array element access expression, the following member must be present:
namespace System.Runtime.CompilerServices
{
public static class RuntimeHelpers
{
public static T[] GetSubArray<T>(T[] array, System.Range range);
}
}
System.IndexSystem.Index
C# no tiene ninguna manera de indexar una colección desde el final, sino que la mayoría de los indexadores usan la noción "desde el principio" o hacen una expresión "length - i".C# has no way of indexing a collection from the end, but rather most indexers use the "from start" notion, or do a "length - i" expression. Presentamos una nueva expresión index que significa "desde el final".We introduce a new Index expression that means "from the end". La característica presentará un nuevo operador "hat" de prefijo unario.The feature will introduce a new unary prefix "hat" operator. Su operando único debe ser convertible a System.Int32 .Its single operand must be convertible to System.Int32. Se reduce a la llamada al método System.Index de generador adecuado.It will be lowered into the appropriate System.Index factory method call.
Aumentamos la gramática para unary_expression con el siguiente formato de sintaxis adicional:We augment the grammar for unary_expression with the following additional syntax form:
unary_expression
: '^' unary_expression
;
A esto se le llama el operador index from end.We call this the index from end operator. El índice predefinido de los operadores finales es el siguiente:The predefined index from end operators are as follows:
System.Index operator ^(int fromEnd);
El comportamiento de este operador solo se define para valores de entrada mayores o iguales que cero.The behavior of this operator is only defined for input values greater than or equal to zero.
Ejemplos:Examples:
var array = new int[] { 1, 2, 3, 4, 5 };
var thirdItem = array[2]; // array[2]
var lastItem = array[^1]; // array[new Index(1, fromEnd: true)]
System.RangeSystem.Range
C# no tiene ninguna manera sintáctica de acceder a "intervalos" o "segmentos" de colecciones.C# has no syntactic way to access "ranges" or "slices" of collections. Normalmente, los usuarios se ven obligados a implementar estructuras complejas para filtrar o operar en segmentos de memoria o recurrir a métodos LINQ como list.Skip(5).Take(2) .Usually users are forced to implement complex structures to filter/operate on slices of memory, or resort to LINQ methods like list.Skip(5).Take(2). Con la adición de y otros tipos similares, es más importante tener este tipo de operación admitida en un nivel más profundo en el lenguaje o tiempo de ejecución, y tener la System.Span<T> interfaz unificada.With the addition of System.Span<T> and other similar types, it becomes more important to have this kind of operation supported on a deeper level in the language/runtime, and have the interface unified.
El lenguaje presentará un nuevo operador de intervalo x..y .The language will introduce a new range operator x..y. Es un operador de infijo binario que acepta dos expresiones.It is a binary infix operator that accepts two expressions. Cualquiera de los operandos se puede omitir (ejemplos a continuación) y deben poder convertirse a System.Index .Either operand can be omitted (examples below), and they have to be convertible to System.Index. Se bajará a la llamada al método System.Range de generador adecuado.It will be lowered to the appropriate System.Range factory method call.
Reemplazamos las reglas de gramática de C# multiplicative_expression por lo siguiente (con el fin de introducir un nuevo nivel de prioridad):We replace the C# grammar rules for multiplicative_expression with the following (in order to introduce a new precedence level):
range_expression
: unary_expression
| range_expression? '..' range_expression?
;
multiplicative_expression
: range_expression
| multiplicative_expression '*' range_expression
| multiplicative_expression '/' range_expression
| multiplicative_expression '%' range_expression
;
Todas las formas del operador de intervalo tienen la misma prioridad.All forms of the range operator have the same precedence. Este nuevo grupo de precedencia es menor que los operadores unarios y mayor que los operadores aritméticos multiplicativos.This new precedence group is lower than the unary operators and higher than the multiplicative arithmetic operators.
Llamamos al .. operador el operador de intervalo.We call the .. operator the range operator. El operador de intervalo integrado se puede entender aproximadamente para corresponder a la invocación de un operador integrado de esta forma:The built-in range operator can roughly be understood to correspond to the invocation of a built-in operator of this form:
System.Range operator ..(Index start = 0, Index end = ^0);
Ejemplos:Examples:
var array = new int[] { 1, 2, 3, 4, 5 };
var slice1 = array[2..^3]; // array[new Range(2, new Index(3, fromEnd: true))]
var slice2 = array[..^3]; // array[Range.EndAt(new Index(3, fromEnd: true))]
var slice3 = array[2..]; // array[Range.StartAt(2)]
var slice4 = array[..]; // array[Range.All]
Además, debe tener una conversión implícita de , para evitar la necesidad de sobrecargar la combinación de enteros e índices sobre firmas System.Index System.Int32 multidimensionales.Moreover, System.Index should have an implicit conversion from System.Int32, in order to avoid the need to overload mixing integers and indexes over multi-dimensional signatures.
Agregar compatibilidad con índices e intervalos a los tipos de biblioteca existentesAdding Index and Range support to existing library types
Compatibilidad con índices implícitosImplicit Index support
El lenguaje proporcionará un miembro del indexador de instancia con un único parámetro de tipo Index para los tipos que cumplen los criterios siguientes:The language will provide an instance indexer member with a single parameter of type Index for types which meet the following criteria:
- El tipo es Countable.The type is Countable.
- El tipo tiene un indexador de instancia accesible que toma un único
intcomo argumento.The type has an accessible instance indexer which takes a singleintas the argument. - El tipo no tiene un indexador de instancia accesible que toma como
Indexprimer parámetro.The type does not have an accessible instance indexer which takes anIndexas the first parameter. debeIndexser el único parámetro o los parámetros restantes deben ser opcionales.TheIndexmust be the only parameter or the remaining parameters must be optional.
Un tipo es Countable si tiene una propiedad denominada o con Length un Count getter accesible y un tipo de valor devuelto de int .A type is Countable if it has a property named Length or Count with an accessible getter and a return type of int. El lenguaje puede usar esta propiedad para convertir una expresión de tipo en un en el punto de la expresión sin necesidad de Index usar el tipo en int Index absoluto.The language can make use of this property to convert an expression of type Index into an int at the point of the expression without the need to use the type Index at all. En caso de Length que estén Count presentes y , se Length preferirá .In case both Length and Count are present, Length will be preferred. Para simplificar en el futuro, la propuesta usará el nombre Length para representar Count o Length .For simplicity going forward, the proposal will use the name Length to represent Count or Length.
Para estos tipos, el lenguaje actuará como si hubiera un miembro de indexador del formulario, donde es el tipo de valor devuelto del indexador basado, incluidas las anotaciones T this[Index index] T de int ref estilo.For such types, the language will act as if there is an indexer member of the form T this[Index index] where T is the return type of the int based indexer including any ref style annotations. El nuevo miembro tendrá los mismos miembros get y set con accesibilidad que el int indexador.The new member will have the same get and set members with matching accessibility as the int indexer.
El nuevo indexador se implementará convirtiendo el argumento de tipo en un y emitiendo una llamada Index int al int indexador basado.The new indexer will be implemented by converting the argument of type Index into an int and emitting a call to the int based indexer. Para fines de discusión, vamos a usar el ejemplo de receiver[expr] .For discussion purposes, let's use the example of receiver[expr]. La conversión de expr a se producirá de la siguiente int manera:The conversion of expr to int will occur as follows:
- Cuando el argumento tiene el formato
^expr2y el tipo de es , seexpr2inttraducirá areceiver.Length - expr2.When the argument is of the form^expr2and the type ofexpr2isint, it will be translated toreceiver.Length - expr2. - De lo contrario, se traducirá como
expr.GetOffset(receiver.Length).Otherwise, it will be translated asexpr.GetOffset(receiver.Length).
Esto permite a los desarrolladores usar la Index característica en tipos existentes sin necesidad de modificación.This allows for developers to use the Index feature on existing types without the need for modification. Por ejemplo:For example:
List<char> list = ...;
var value = list[^1];
// Gets translated to
var value = list[list.Count - 1];
Las expresiones y se desbordarán según corresponda para garantizar que los efectos secundarios solo receiver Length se ejecuten una vez.The receiver and Length expressions will be spilled as appropriate to ensure any side effects are only executed once. Por ejemplo:For example:
class Collection {
private int[] _array = new[] { 1, 2, 3 };
public int Length {
get {
Console.Write("Length ");
return _array.Length;
}
}
public int this[int index] => _array[index];
}
class SideEffect {
Collection Get() {
Console.Write("Get ");
return new Collection();
}
void Use() {
int i = Get()[^1];
Console.WriteLine(i);
}
}
Este código imprimirá "Get Length 3".This code will print "Get Length 3".
Compatibilidad implícita con intervalosImplicit Range support
El lenguaje proporcionará un miembro del indexador de instancia con un único parámetro de tipo Range para los tipos que cumplen los criterios siguientes:The language will provide an instance indexer member with a single parameter of type Range for types which meet the following criteria:
- El tipo es Countable.The type is Countable.
- El tipo tiene un miembro accesible denominado
Sliceque tiene dos parámetros de tipoint.The type has an accessible member namedSlicewhich has two parameters of typeint. - El tipo no tiene un indexador de instancia que toma un único
Rangecomo primer parámetro.The type does not have an instance indexer which takes a singleRangeas the first parameter. debeRangeser el único parámetro o los parámetros restantes deben ser opcionales.TheRangemust be the only parameter or the remaining parameters must be optional.
Para estos tipos, el lenguaje se enlazará como si hubiera un miembro de indexador del formulario, donde es el tipo de valor devuelto del método, incluidas las anotaciones T this[Range range] T de Slice ref estilo.For such types, the language will bind as if there is an indexer member of the form T this[Range range] where T is the return type of the Slice method including any ref style annotations. El nuevo miembro también tendrá accesibilidad que coincida con Slice .The new member will also have matching accessibility with Slice.
Cuando el indexador basado se enlaza en una expresión denominada , se reduce mediante la conversión de la expresión en dos valores que luego se pasan Range receiver al método Range Slice .When the Range based indexer is bound on an expression named receiver, it will be lowered by converting the Range expression into two values that are then passed to the Slice method. Para fines de discusión, vamos a usar el ejemplo de receiver[expr] .For discussion purposes, let's use the example of receiver[expr].
El primer argumento de Slice se obtendrá mediante la conversión de la expresión con tipo de intervalo de la siguiente manera:The first argument of Slice will be obtained by converting the range typed expression in the following way:
- Cuando
exprtiene el formato (donde se puede omitir) y tiene el tipo , seexpr1..expr2expr2expr1intemitirá comoexpr1.Whenexpris of the formexpr1..expr2(whereexpr2can be omitted) andexpr1has typeint, then it will be emitted asexpr1. - Cuando
exprtiene el formato^expr1..expr2(donde se puedeexpr2omitir), se emitirá comoreceiver.Length - expr1.Whenexpris of the form^expr1..expr2(whereexpr2can be omitted), then it will be emitted asreceiver.Length - expr1. - Cuando
exprtiene el formato..expr2(donde se puedeexpr2omitir), se emitirá como0.Whenexpris of the form..expr2(whereexpr2can be omitted), then it will be emitted as0. - De lo contrario, se emitirá como
expr.Start.GetOffset(receiver.Length).Otherwise, it will be emitted asexpr.Start.GetOffset(receiver.Length).
Este valor se volverá a usar en el cálculo del segundo Slice argumento.This value will be re-used in the calculation of the second Slice argument. Al hacerlo, se hará referencia a él como start .When doing so it will be referred to as start. El segundo argumento de Slice se obtendrá mediante la conversión de la expresión con tipo de intervalo de la siguiente manera:The second argument of Slice will be obtained by converting the range typed expression in the following way:
- Cuando
exprtiene el formato (donde se puede omitir) y tiene el tipo , seexpr1..expr2expr1expr2intemitirá comoexpr2 - start.Whenexpris of the formexpr1..expr2(whereexpr1can be omitted) andexpr2has typeint, then it will be emitted asexpr2 - start. - Cuando
exprtiene el formatoexpr1..^expr2(donde se puedeexpr1omitir), se emitirá como(receiver.Length - expr2) - start.Whenexpris of the formexpr1..^expr2(whereexpr1can be omitted), then it will be emitted as(receiver.Length - expr2) - start. - Cuando
exprtiene el formatoexpr1..(donde se puedeexpr1omitir), se emitirá comoreceiver.Length - start.Whenexpris of the formexpr1..(whereexpr1can be omitted), then it will be emitted asreceiver.Length - start. - De lo contrario, se emitirá como
expr.End.GetOffset(receiver.Length) - start.Otherwise, it will be emitted asexpr.End.GetOffset(receiver.Length) - start.
Las receiver Length expresiones , y se desbordarán según corresponda para asegurarse de que los efectos secundarios solo se expr ejecutan una vez.The receiver, Length, and expr expressions will be spilled as appropriate to ensure any side effects are only executed once. Por ejemplo:For example:
class Collection {
private int[] _array = new[] { 1, 2, 3 };
public int Length {
get {
Console.Write("Length ");
return _array.Length;
}
}
public int[] Slice(int start, int length) {
var slice = new int[length];
Array.Copy(_array, start, slice, 0, length);
return slice;
}
}
class SideEffect {
Collection Get() {
Console.Write("Get ");
return new Collection();
}
void Use() {
var array = Get()[0..2];
Console.WriteLine(array.Length);
}
}
Este código imprimirá "Get Length 2".This code will print "Get Length 2".
El lenguaje tendrá especial mayúsculas de minúsculas en los siguientes tipos conocidos:The language will special case the following known types:
string: el métodoSubstringse usará en lugar deSlice.string: the methodSubstringwill be used instead ofSlice.array: el métodoSystem.Runtime.CompilerServices.RuntimeHelpers.GetSubArrayse usará en lugar deSlice.array: the methodSystem.Runtime.CompilerServices.RuntimeHelpers.GetSubArraywill be used instead ofSlice.
AlternativasAlternatives
Los nuevos operadores ( ^ y ) son el nivel de sugar .. sintáctico.The new operators (^ and ..) are syntactic sugar. La funcionalidad se puede implementar mediante llamadas explícitas a los métodos de generador y , pero dará lugar a un código mucho más reutilizable y la experiencia no será System.Index System.Range específica.The functionality can be implemented by explicit calls to System.Index and System.Range factory methods, but it will result in a lot more boilerplate code, and the experience will be unintuitive.
Representación de ILIL Representation
Estos dos operadores se reducirán a llamadas regulares de indexador o método, sin cambios en las capas del compilador posteriores.These two operators will be lowered to regular indexer/method calls, with no change in subsequent compiler layers.
Comportamiento en tiempo de ejecuciónRuntime behavior
- El compilador puede optimizar los indexadores para tipos integrados, como matrices y cadenas, y reducir la indexación a los métodos existentes adecuados.Compiler can optimize indexers for built-in types like arrays and strings, and lower the indexing to the appropriate existing methods.
System.Indexse produce si se construye con un valor negativo.System.Indexwill throw if constructed with a negative value.^0no inicia, pero se traduce en la longitud de la colección o enumerable a la que se proporciona.^0does not throw, but it translates to the length of the collection/enumerable it is supplied to.Range.Alles semánticamente equivalente a0..^0y se puede deconstruir en estos índices.Range.Allis semantically equivalent to0..^0, and can be deconstructed to these indices.
ConsideracionesConsiderations
Detección de indexables basados en ICollectionDetect Indexable based on ICollection
La inspiración de este comportamiento fueron los inicializadores de colección.The inspiration for this behavior was collection initializers. Usar la estructura de un tipo para transmitir que ha optado por una característica.Using the structure of a type to convey that it had opted into a feature. En el caso de los inicializadores de colección, los tipos pueden participar en la característica implementando la interfaz IEnumerable (no genérica).In the case of collection initializers types can opt into the feature by implementing the interface IEnumerable (non generic).
Esta propuesta requiere inicialmente que los tipos ICollection implementen para calificarse como indexables.This proposal initially required that types implement ICollection in order to qualify as Indexable. Sin embargo, esto requiere una serie de casos especiales:That required a number of special cases though:
ref struct: no pueden implementar interfaces, pero tipos comoSpan<T>son ideales para la compatibilidad con índices o intervalos.ref struct: these cannot implement interfaces yet types likeSpan<T>are ideal for index / range support.string: no implementa yICollectionagrega que tiene un graninterfacecosto.string: does not implementICollectionand adding thatinterfacehas a large cost.
Esto significa que ya se necesitan mayúsculas y minúsculas especiales para los tipos clave.This means to support key types special casing is already needed. El uso de mayúsculas y minúsculas especial de es menos interesante, ya que el lenguaje lo hace en otras áreas string (reducción, foreach constantes, etc.). El uso de mayúsculas y minúsculas especial de es más importante, ya que es un uso especial de ref struct mayúsculas y minúsculas de una clase completa de tipos.The special casing of string is less interesting as the language does this in other areas (foreach lowering, constants, etc ...). The special casing of ref struct is more concerning as it's special casing an entire class of types. Se etiquetan como indexables si simplemente tienen una propiedad denominada Count con un tipo de valor devuelto de int .They get labeled as Indexable if they simply have a property named Count with a return type of int.
Después de considerar el diseño se normalizó para decir que cualquier tipo que tenga una propiedad con un Count / Length tipo de valor devuelto int de es Indexable.After consideration the design was normalized to say that any type which has a property Count / Length with a return type of int is Indexable. Esto quita todas las mayúsculas y minúsculas especiales, incluso para string las matrices y .That removes all special casing, even for string and arrays.
Detectar solo recuentoDetect just Count
La detección en los nombres Count de propiedad o complica un poco el Length diseño.Detecting on the property names Count or Length does complicate the design a bit. Elegir solo uno para estandarizar no es suficiente, ya que termina excluyendo un gran número de tipos:Picking just one to standardize though is not sufficient as it ends up excluding a large number of types:
- Use
Length: excluye prácticamente todas las colecciones de System.Collections y sub namespaces.UseLength: excludes pretty much every collection in System.Collections and sub-namespaces. Tienden a derivar deICollectiony, por tanto, prefierenCountla longitud.Those tend to derive fromICollectionand hence preferCountover length. - Use : excluye , matrices y
Countla mayoría de los tiposstringSpan<T>ref structbasadosUseCount: excludesstring, arrays,Span<T>and mostref structbased types
La complicación adicional en la detección inicial de tipos indexables se compensa por su simplificación en otros aspectos.The extra complication on the initial detection of Indexable types is outweighed by its simplification in other aspects.
Elección del segmento como nombreChoice of Slice as a name
Se ha elegido el nombre, ya que es el nombre estándar de facto para las operaciones de estilo Slice de segmento en .NET.The name Slice was chosen as it's the de-facto standard name for slice style operations in .NET. A partir de netcoreapp2.1, todos los tipos de estilo de intervalo usan el nombre Slice para las operaciones de cortar.Starting with netcoreapp2.1 all span style types use the name Slice for slicing operations. Antes de netcoreapp2.1, en realidad no hay ningún ejemplo de la sección para buscar un ejemplo.Prior to netcoreapp2.1 there really aren't any examples of slicing to look to for an example. Tipos como , , habría sido ideal para lalicación, pero el concepto no existía List<T> ArraySegment<T> cuando se SortedList<T> agregaron tipos.Types like List<T>, ArraySegment<T>, SortedList<T> would've been ideal for slicing but the concept didn't exist when types were added.
Por lo Slice tanto, al ser el único ejemplo, se eligió como nombre.Thus, Slice being the sole example, it was chosen as the name.
Conversión de tipos de destino de índiceIndex target type conversion
Otra manera de ver la Index transformación en una expresión de indexador es como una conversión de tipo de destino.Another way to view the Index transformation in an indexer expression is as a target type conversion. En lugar de enlazar como si hubiera un miembro con el formato , el lenguaje asigna en su lugar una conversión return_type this[Index] con tipo de destino a int .Instead of binding as if there is a member of the form return_type this[Index], the language instead assigns a target typed conversion to int.
Este concepto se podría generalizar para todo el acceso a miembros en tipos countable.This concept could be generalized to all member access on Countable types. Cada vez que se usa una expresión con tipo como argumento para una invocación de miembro de instancia y el receptor es Countable, la expresión tendrá una conversión Index de tipo de destino a int .Whenever an expression with type Index is used as an argument to an instance member invocation and the receiver is Countable then the expression will have a target type conversion to int. Las invocaciones de miembro aplicables a esta conversión incluyen métodos, indexadores, propiedades, métodos de extensión, etc. Solo se excluyen los constructores, ya que no tienen ningún receptor.The member invocations applicable for this conversion include methods, indexers, properties, extension methods, etc ... Only constructors are excluded as they have no receiver.
La conversión de tipos de destino se implementará como se muestra a continuación para cualquier expresión que tenga un tipo de Index .The target type conversion will be implemented as follows for any expression which has a type of Index. Para fines de discusión, use el ejemplo de receiver[expr] :For discussion purposes lets use the example of receiver[expr]:
- Cuando
exprtiene el formato y el tipo de es , se^expr2expr2inttraducirá areceiver.Length - expr2.Whenexpris of the form^expr2and the type ofexpr2isint, it will be translated toreceiver.Length - expr2. - De lo contrario, se traducirá como
expr.GetOffset(receiver.Length).Otherwise, it will be translated asexpr.GetOffset(receiver.Length).
Las expresiones y se desbordarán según corresponda para asegurarse de que los efectos secundarios solo receiver Length se ejecuten una vez.The receiver and Length expressions will be spilled as appropriate to ensure any side effects are only executed once. Por ejemplo:For example:
class Collection {
private int[] _array = new[] { 1, 2, 3 };
public int Length {
get {
Console.Write("Length ");
return _array.Length;
}
}
public int GetAt(int index) => _array[index];
}
class SideEffect {
Collection Get() {
Console.Write("Get ");
return new Collection();
}
void Use() {
int i = Get().GetAt(^1);
Console.WriteLine(i);
}
}
Este código imprimirá "Get Length 3".This code will print "Get Length 3".
Esta característica sería beneficiosa para cualquier miembro que tuviera un parámetro que representara un índice.This feature would be beneficial to any member which had a parameter that represented an index. Por ejemplo, List<T>.InsertAt.For example List<T>.InsertAt. Esto también tiene la posibilidad de confusión, ya que el lenguaje no puede proporcionar ninguna guía sobre si una expresión está pensada o no para la indexación.This also has the potential for confusion as the language can't give any guidance as to whether or not an expression is meant for indexing. Todo lo que puede hacer es convertir cualquier Index expresión en al invocar un miembro en un tipo int Countable.All it can do is convert any Index expression to int when invoking a member on a Countable type.
Restricciones:Restrictions:
- Esta conversión solo es aplicable cuando la expresión con tipo
Indexes directamente un argumento para el miembro.This conversion is only applicable when the expression with typeIndexis directly an argument to the member. No se aplicaría a ninguna expresión anidada.It would not apply to any nested expressions.
Decisiones tomadas durante la implementaciónDecisions made during implementation
- Todos los miembros del patrón deben ser miembros de instanciaAll members in the pattern must be instance members
- Si se encuentra un método Length pero tiene el tipo de valor devuelto incorrecto, continúe buscando Count.If a Length method is found but it has the wrong return type, continue looking for Count
- El indexador usado para el patrón Index debe tener exactamente un parámetro int.The indexer used for the Index pattern must have exactly one int parameter
- El método Slice usado para el patrón Range debe tener exactamente dos parámetros int.The Slice method used for the Range pattern must have exactly two int parameters
- Al buscar los miembros de patrón, buscamos definiciones originales, no miembros construidosWhen looking for the pattern members, we look for original definitions, not constructed members