¿Hay alguna manera de negar una función que devuelve Task<bool> sin ejecutarla explícitamente usando async / await? Tengo varias comprobaciones únicas en mis FluentValidators. Quería hacer algo como esto:

public Task<bool> HasUniqueNameAsync(Entity entity, string propName, CancellationToken cancellationToken = default(CancellationToken))
{
    return _dbContext.Entities.AnyAsync(x => !(x.PropName == propName && x.Id != entity.Id));
}

Sin embargo, en lugar de negar el valor booleano, la consulta LINQ se traduce a

x.PropName != propName && x.Id == entity.Id

Lo cual no es equivalente. Por el momento, he actualizado mis funciones de verificación únicas para que se vean así:

public async Task<bool> HasUniqueNameAsync(Entity entity, string propName, CancellationToken cancellationToken = default(CancellationToken))
{
    return !await _dbContext.Entities.AnyAsync(x => x.PropName == propName && x.Id != entity.Id);
}

¿Hay alguna manera de agregar una negación sin usar explícitamente async / await?

1
Sam 12 dic. 2019 a las 19:03

2 respuestas

La mejor respuesta

Hay una forma lógica de hacer esto. Actualmente está marcando "si hay alguna coincidencia" y lo está negando. Lógicamente, "ninguna coincidencia" es lo mismo que "no todas coinciden". Entonces, si su código actual es:

public async Task<bool> HasUniqueNameAsync(Entity entity, string propName, CancellationToken cancellationToken = default(CancellationToken))
{
    return !await _dbContext.Entities.AnyAsync(x => x.PropName == propName && x.Id != entity.Id);
}

Entonces puedes mover la negación a la función haciendo esto:

public Task<bool> HasUniqueNameAsync(Entity entity, string propName, CancellationToken cancellationToken = default(CancellationToken))
{
    return _dbContext.Entities.AllAsync(x => !(x.PropName == propName && x.Id != entity.Id));
}

Alternativamente, puede usar continuaciones para agregar operaciones a una tarea que se ejecutará cuando finalice:

public async Task<bool> HasUniqueNameAsync(Entity entity, string propName, CancellationToken cancellationToken = default(CancellationToken))
{
    return !await _dbContext.Entities
        .AnyAsync(x => x.PropName == propName && x.Id != entity.Id)
        .ContinueWith(x => !x.Result);
}

Finalmente, noto que no estás usando ese CancellationToken en tu código. Debe pasar eso a AnyAsync() (y también a ContinueWith() si elige ir por esa ruta).

1
anaximander 12 dic. 2019 a las 16:36

Puede devolver un tarea de continuación negando el resultado de la tarea AnyAsync:

public Task<bool> HasUniqueNameAsync(Entity entity, string propName, CancellationToken cancellationToken = default(CancellationToken))
{
    return _dbContext.Entities
        .AnyAsync(x => x.PropName == propName && x.Id != entity.Id))
        .ContinueWith(continuation => !continuation.Result, cancellationToken );
}
3
devNull 12 dic. 2019 a las 16:31