martes, 4 de junio de 2019
Seguimos analizando las novedades que traerá C# 8, y esta vez vamos a detenernos en una característica que aportará algo más de agilidad a la hora de trocear o acceder a elementos de arrays y algunos tipos de colecciones similares, como
Como muchas otras características del lenguaje, se trata de algunos azucarillos sintácticos creados en torno a dos nuevos tipos añadidos a las bibliotecas básicas del framework: las estructuras
Índices de arrays con
Hasta esta versión de C#, la forma natural de acceder a un elemento específico de un array era indicando el entero que representaba su posición en el mismo. Por ejemplo, con
La nueva estructura
En primer lugar, el tipo
Y aquí es donde entra en juego el nuevo uso del operador hat (sombrero) ^ de C# 8. Este operador es un mero azucarillo sintáctico para facilitar la creación de índices desde el final, como hacíamos con
Publicado en: www.variablenotfound.com.
Span<T>
.Como muchas otras características del lenguaje, se trata de algunos azucarillos sintácticos creados en torno a dos nuevos tipos añadidos a las bibliotecas básicas del framework: las estructuras
System.Index
y System.Range
. Por esta razón, para utilizar estos elementos no sólo es necesario disponer de nuevos compiladores, sino también de nuevas versiones del framework.Recordad que a día de hoy ya se puede probar C# 8 en Visual Studio 2019 o directamente desde la interfaz de línea de comandos de .NET Core.
Índices de arrays con System.Index
Hasta esta versión de C#, la forma natural de acceder a un elemento específico de un array era indicando el entero que representaba su posición en el mismo. Por ejemplo, con arr[0]
podíamos acceder al primer elemento de la colección, o con arr[arr.Length-1]
al último.La nueva estructura
Index
proporciona una fórmula para almacenar y gestionar índices usando tipos específicamente diseñados para ello, lo que permite añadir algo más de flexibilidad al resultado. Su uso básico, que no parece demasiado útil, es el siguiente:var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
Index i0 = new Index(0);
Index i1 = new Index(1);
Index i7 = new Index(7);
Console.WriteLine(primes[i0]); // 2
Console.WriteLine(primes[i1]); // 3
Console.WriteLine(primes[i7]); // 19
Así al vistazo no parece algo que valga demasiado la pena, ¿verdad? Bueno, pues como aportación interesante, a la hora de crear un índice podemos indicar si la referencia la hacemos desde el principio o desde el final de la secuencia:var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
Index fromStart3 = new Index(3); // Por defecto, 'fromEnd' es falso
Index fromEnd1 = new Index(1, fromEnd: true);
Index fromEnd8 = new Index(8, fromEnd: true);
Console.WriteLine(primes[fromStart3]); // 7
Console.WriteLine(primes[fromEnd1]); // 19
Console.WriteLine(primes[fromEnd8]); // 2
¡Alto ahí! Fijaos en un detalle sumamente importante: cuando comenzamos por el final, el índice 1 es el primer elemento. O en otras palabras, un acceso desde el final al índice 0 daría un error, porque este elemento sería posterior al último item de la colección; sin embargo, cuando contamos desde el principio, el índice cero es el primero.var ceroFromStart = new Index(0);
var ceroFromEnd = new Index(0, fromEnd: true);
Console.WriteLine(primes[ceroFromStart]); // 2
Console.WriteLine(primes[ceroFromEnd]); // Error: IndexOutOfRangeException
Por último, cabe añadir que la estructura Index
dispone de algunos métodos estáticos para agilizar la creación de índices, como Index.FromStart()
o Index.FromEnd()
, o para obtener referencias al comienzo y final (recordad, ¡fuera del array!) con Index.Start
e Index.End
respectivamente:Index fromEnd3A = Index.FromEnd(3);
Index fromEnd3B = new Index(3, fromEnd: true);
Console.WriteLine(fromEnd3A.Equals(fromEnd3A)); // True
var start = Index.Start;
var alsoStart = Index.FromStart(0);
Console.WriteLine(start.Equals(alsoStart)); // True
Conversiones implícitas y el operador hat ^
Anteriormente hemos visto lo fácil que es crear índices y utilizarlos para acceder a los elementos de una colección. Pero, obviamente, esto no podía quedar ahí.En primer lugar, el tipo
Index
dispone de conversiones implícitas hacia y desde int
, lo que quiere decir que normalmente podremos utilizar estos dos tipos indistintamente, como se muestra en el siguiente ejemplo:var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
Index fromStart3a = new Index(3);
Index fromStart3b = 3;
int fromStart3c = 3;
Console.WriteLine(primes[fromStart3a]); // 7
Console.WriteLine(primes[fromStart3b]); // 7
Console.WriteLine(primes[fromStart3c]); // 7
Console.WriteLine(fromStart3a.Equals(fromStart3c)); // True
Vale, esto simplifica la codificación de índices comenzando por el principio, igual que lo hemos hecho siempre con enteros, pero, ¿qué ocurre con la indexación desde el final?Y aquí es donde entra en juego el nuevo uso del operador hat (sombrero) ^ de C# 8. Este operador es un mero azucarillo sintáctico para facilitar la creación de índices desde el final, como hacíamos con
Index.FromEnd()
, pero de forma más compacta. Veamos unos ejemplos:var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
var fromEnd2A = Index.FromEnd(2);
var fromEnd2B = ^2; // = Index.FromEnd(2)
Console.WriteLine(primes[fromEnd2A] == primes[fromEnd2B]); // True
Console.WriteLine(primes[fromEnd2B]); // 17
En el siguiente post veremos cómo la nueva estructura Range
permite especificar rangos o extraer porciones de colecciones indicando los límites superiores e inferiores, y cómo se vale de Index
para ello.Publicado en: www.variablenotfound.com.
Patrocinador
Oferta de empleo: Desarrollador web .NET (Barcelona)
Si tienes más de dos años de experiencia desarrollando aplicaciones web ASP.NET/.NET Core y te gustan los retos tecnológicos, ven a trabajar con
nosotros a un proyecto de escala global que está revolucionando la atención al cliente en plataformas e-commerce.
2 Comentarios:
Muy bueno, gracias por el update
Me alegra saber que te resulta interesante. Y muchas gracias por comentar :)
Saludos!
Enviar un nuevo comentario