C # use la expresión lambda asíncrona con return bool en la extensión Enumerable.All

Sep 28 2020

Tengo el siguiente asyncmétodo

private async Task<bool> HasPolicy(AuthorizationFilterContext context, string policy)
{
    var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, policy);
    return authorized.Succeeded;
}

Me gustaría usarlo en Enumerable.Ally Enumerable.Anyextensión

var result1 = IsAndPolicy
    ? policys.All(async x => await HasPolicy(context, x))
    : policys.Any(async x => await HasPolicy(context, x));

Pero el código anterior obtiene el siguiente error

Error CS4010 No se puede convertir la expresión lambda asíncrona al tipo de delegado 'Func <string, bool>'. Una expresión lambda asíncrona puede devolver void, Task o Task, ninguno de los cuales es convertible a 'Func <string, bool>'.

Respuestas

4 00110001 Sep 28 2020 at 15:07

Un enfoque sería proyectar a unIEnumerable<Task<bool>>

var results = await Task.WhenAll(policys.Select(x => HasPolicy(context, x)));

var result1 = IsAndPolicy 
   ? results.All(x => x)                
   : results.Any(x => x);

El problema con este enfoque es que está procesando todos los elementos potencialmente innecesariamente.

2 PanagiotisKanavos Sep 28 2020 at 15:26

La respuesta de Michael Randall produce el resultado lógico correcto pero tiene que evaluar todas las políticas, aunque en ambos casos la evaluación puede tener un cortocircuito, por el primer falseresultado para Allo el primer trueresultado para Any.

Esto se puede evitar convirtiendo las tareas a IAsyncenumerable<T>y usando System.Linq.Async :

var resultTasks=policies.ToAsyncEnumerable()
                        .Select(async x => await HasPolicy(context, x));

var result1 = await (IsAndPolicy 
                       ? resultTasks.AllAsync(x => x)                
                       : resultTasks.AnyAsync(x => x));