C# 7.0 – Specification – Generalized async return types
Dentro de C# 7.0, podemos encontrar una nueva especificación del lenguaje relativa a lo que en inglés se denomina como Generalized async return types.
Me atrevería a traducir al castellano esta característica como «devolución generalizada de tipos de valor asíncronos«.
Básicamente, los métodos async de C# antes de la especificación 7.0 del lenguaje, debían devolver un void (para un controlador de eventos), Task (para un método asíncrono y que no devuelve ningún valor), o un Task<T> (para un método asíncrono que devuelve un valor).
Con C# 7.0, se nos permite devolver otros tipos de datos en métodos async.
Para ello, tenemos un tipo struct ValueTask<T>.
Un método asincróno podrá devolver cualquier tipo que tenga un método GetAwaiter accesible.
Task y Task<T> son tipos por referencia.
Esto significa que la asignación de memoria sobre todo para bucles, puede afectar en el rendimiento.
El objetivo de ValueTask<T> es reducir el número de asignaciones sobre todo en escenarios donde el buffering sea requerido, pudiendo obtener una mejora apreciable de rendimiento.
De esta forma, se devolverá un tipo de valor en lugar de un tipo de valor por referencia, evitando asignaciones extras de memoria.
Dentro del ensamblado System.Threading.Tasks.Extensions.dll, y en concreto dentro de la estructura System.Threading.Tasks.ValueTask<TResult>, encontraremos lo que buscamos.
Algo que puedes consultar en el siguiente enlace.
Si queremos utilizar esta característica, deberemos utilizar el paquete System.Threading.Tasks.Extensions de NuGet que encotraremos en el siguiente enlace.
Un ejemplo básico de esta característica sería la que se indica en las siguientes instrucciones de código:
private static async ValueTask<int> GetValues() { Console.WriteLine("Getting values"); int value1 = await GetRandomValue(); int value2 = await GetRandomValue(); Console.WriteLine($"\tValue 1 => {value1}"); Console.WriteLine($"\tValue 2 => {value2}"); return value1 + value2; } private static async ValueTask<int> GetRandomValue() { random = random == null ? new Random() : random; await Task.Delay(100); int value = random.Next(1, 101); return value; }
La llamada a esta funcionalidad desde una aplicación de consola por ejemplo, quedaría de la siguiente forma:
Console.WriteLine($"The sum of the values is {GetValues().Result}");
¡Happy Coding!