Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
Mostrando entradas con la etiqueta c#8. Mostrar todas las entradas
Mostrando entradas con la etiqueta c#8. Mostrar todas las entradas
martes, 22 de octubre de 2019
.NET Core Hasta ahora, la generación o enumeración de secuencias era un proceso puramente síncrono. Por ejemplo, si queríamos recorrer un IEnumerable con un bucle foreach, cada uno de los elementos debía existir previamente en la colección o bien ser generado de forma síncrona.

Por ejemplo, en el siguiente código no teníamos una forma razonable de implementarlo si la obtención de cada uno de los valores retornados desde el método generador tuviera que ser asíncrona:
foreach (var i in GetNumbers())
{
    Console.WriteLine(i);
}

IEnumerable<int> GetNumbers()
{
    for (var i = 0; i < 1000_000_000; i++)
    {
        var a = i * 2;   // <-- Esto es una operación síncrona,
        yield return a;  //     ¿cómo haríamos si en lugar de esta operación síncrona
                         //     necesitásemos hacer una llamada asíncrona para obtenerlo?
    }
}
Aunque convertir el método GetNumbers() en asíncrono pudiera parecer una alternativa razonable, en realidad no lo es; de hecho, los resultados no llegarían al cliente hasta que hubiéramos generado todos los valores, por lo que sería peor que la primera opción en términos de rendimiento y ocupación de memoria:
foreach (var i in await GetNumbersAsync())
{
    Console.WriteLine(i);
}

async Task<IEnumerable<int>> GetNumbersAsync()
{
    var list = new List<int>();
    for (var i = 0; i < 1000_000_000; i++)
    {
        var a = await Task.FromResult(i * 2); // <-- Aquí generamos los valores usando asincronía,
        list.Add(a);                          //     pero el consumidor seguirá esperando hasta
                                              //     que los hayamos generado todos.
    }
    return list;                              // <-- Aquí retornamos la colección completa
}
En este último caso la llamada a GetNumbersAsync() se ejecutaría de forma asíncrona, es decir, daríamos la oportunidad al hilo de ejecución actual de dedicarse a otros menesteres mientras la llamada es realizada, desde el punto de vista de su consumidor es a todos los efectos como si se tratara de un método síncrono.

Pues bien, aparte de características mainstream como la implementación por defecto en interfaces, los tipos referencia anulables, índices y rangos o muchas otras, en la última versión del framework y C# 8 se ha introducido el soporte para la generación y consumo de secuencias asíncronas.
martes, 15 de octubre de 2019
.NET Core Seguimos descubriendo perlas en C# 8 que nos harán la vida algo más sencilla a los desarrolladores. En este caso, se trata de una pequeña adición al lenguaje que nos permitirá hacer más claras y concisas determinadas expresiones condicionales.

Para ponernos en situación, imaginemos que tenemos una expresión como la siguiente, donde retornamos el texto "Rojo" cuando le suministramos el valor de enumeración Color.Red, y "Desconocido" en otros casos. Algo fácil de solucionar utilizando el operador condicional ?:
enum Color { Purple, Red, Blue, Orange, Black, Pink, Gray, Green, White };
string GetColorName(Color color)
{
    var str = color == Color.Red ? "Rojo" : "Desconocido";
    return str;
}
Imaginemos ahora que la aplicación evoluciona y debemos añadir otro caso a esta condición, como el soporte para el color azul. No pasa nada, podemos seguir el mismo patrón, aunque empezaremos a notar que esto no va a escalar demasiado porque la legibilidad empieza a resentirse:
var str = color == Color.Red ? "Rojo" : color == Color.Blue ? "Azul" : "Desconocido";

martes, 17 de septiembre de 2019
.NET CoreComo probablemente sabréis, C# 8 hace posible que las interfaces incluyan una implementación por defecto para sus miembros... ¿Pero no habíamos quedado en que las interfaces definían contratos, pero no implementaciones? ¿El mundo se ha vuelto loco?

Pues sí, y creo que no del todo, respectivamente ;)

En este post vamos a echar un primer vistazo a la que creo que es una de las características más controvertidas de la nueva versión del lenguaje.
Nota: aún estamos usando compiladores y tooling preliminar, por lo que lo dicho aquí podría resultar incompleto o inexacto cuando la versión definitiva de C# 8 sea lanzada (en pocos días, vaya ;)
martes, 9 de julio de 2019
.NET Core Cuando, en 1965, el bueno de Tony Hoare introdujo las referencias nulas en el lenguaje ALGOL simplemente "porque era fácil de implementar", no era consciente de que se trataba de un error que a la postre él mismo definiría como su "error del billón de dólares".

De hecho, en el top ten de errores de ejecución de aplicaciones creadas con casi cualquier lenguaje y plataforma, las excepciones o crashes debidos a las referencias nulas son, con diferencia, el tipo de error más frecuente que solemos encontrar.

Pues en este repaso que vamos dando a las novedades principales de C# 8, hemos llegado la que probablemente podría ser la característica más destacada en este entrega, cuyo objetivo es precisamente establecer las bases para que podamos olvidarnos de las referencias no controladas a nulos.
No olvidéis que hasta que sea lanzado oficialmente C# 8, para poder probar sus características hay que hacer algunas cosillas.
martes, 2 de julio de 2019
.NET Core En esta ocasión vamos a ver una pequeña novedad de C# 8 destinada a mejorar la codificación de un escenario muy frecuente: asignar un valor a una variable si ésta es nula.
Recordad que C#8 está aún en preview, y para usarlo hay que seguir los pasos que vimos en un post anterior.
En otras palabras, esta mejora pretende simplificar implementaciones como las siguientes, donde comprobamos si una variable contiene null y, en caso afirmativo, le asignamos un valor:
...
var defaultValue = ... // lo que sea;
var x = GetSomething();

// Usando un bloque if:
if(x == null)
{
    x = defaultValue;
}

// O bien, usando el null coalescing operator:
x = x ?? defaultValue;

martes, 11 de junio de 2019
.NET CoreEn el post anterior vimos que la estructura Index, junto con alguna cortesía del compilador, permitía la especificación de índices en arrays de forma muy sencilla. Veíamos cómo podíamos acceder a elementos concretos utilizando su posición en la colección, tanto contando desde el principio como desde el final:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
Index fromStart = 2;  // = Index.FromStart(2) - conversión implícita
Index fromEnd = ^2;   // = Index.FromEnd(2)

Console.WriteLine(primes[fromStart]); // 5
Console.WriteLine(primes[fromEnd]); // 17
Sin embargo, puede que a Index por sí mismo tampoco le veáis demasiada utilidad... y así es. De hecho, su finalidad es más bien el dar soporte a rangos, una nueva característica de C#8 que nos permitirá referirnos a "porciones" de arrays o colecciones similares usando una sintaxis compacta e integrada en el lenguaje.
martes, 4 de junio de 2019
.NET Core 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 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.
martes, 21 de mayo de 2019
.NET Core La palabra clave using, utilizada tanto en forma de directiva como de instrucción, es una de las más sobrecargadas del lenguaje C#. Es útil para bastantes cosas, como la importación de espacios de nombres, definición de alias de namespaces o tipos, simplificar el acceso a miembros de tipos estáticos, o para especificar bloques o ámbitos de uso de recursos (objetos IDisposable) que deben ser liberados automáticamente.

Centrándonos en este último caso de uso, seguro que en muchas ocasiones habéis escrito código como el siguiente, donde vamos anidando objetos IDisposable para asegurar que al finalizar la ejecución de cada bloque los recursos sean liberados de forma automática:
void DoSomething()
{
    using(var conn = new SqlConnection(...))
    {
        connection.Open();
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = "...";
            using (var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    // ...
                }
            }
        }
    }
}    
Al final, lo que encontramos es código con un nivel de indentación muy alto, y que resulta muy extenso, básicamente porque una gran parte de las líneas las dedicamos sólo a abrir y cerrar llaves. A la postre, esto sólo hace que nuestro código crezca a lo ancho, lo cual no es bueno desde el punto de vista de la simplicidad y facilidad de lectura.