【问题标题】:Negating a Task<bool> without await?不等待就否定 Task<bool>?
【发布时间】:2020-04-06 01:53:12
【问题描述】:

有没有办法在不使用 async/await 显式运行的情况下否定返回 Task&lt;bool&gt; 的函数?我的 FluentValidators 中有几个独特的检查。我想做这样的事情:

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

但是,LINQ 查询不是否定布尔值,而是被转换为

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

这是不等价的。目前,我已经更新了我独特的检查功能,使它们看起来像这样:

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);
}

有没有办法在不显式使用 async/await 的情况下添加否定?

【问题讨论】:

  • !Any(x) == All(!x), Any(!x) != !Any(x)。请注意,数据库会通过输入null 使事情复杂化,因此这些双重转换甚至不总是可能的,并且只有一种“正确”的方式来编写查询。
  • ContinueWith 是一个选项吗?
  • 附注:不要使用ContinueWith。它只是await 的一个更复杂、更容易出错的版本。

标签: c# entity-framework async-await


【解决方案1】:

您可以返回一个 continuation task 否定 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 );
}

【讨论】:

  • 看起来你打败了我。
【解决方案2】:

有一种合乎逻辑的方法可以做到这一点。您当前正在检查“如果有任何匹配”并否定它 - 从逻辑上讲,“没有任何匹配”与“全部不匹配”相同。因此,如果您当前的代码是:

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);
}

然后你可以通过这样做将否定移到函数中:

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

或者,您可以使用延续将操作附加到要在完成时执行的任务上:

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);
}

最后,我注意到您没有在代码中使用 CancellationToken。你应该把它传递给AnyAsync()(如果你选择走那条路,也应该传递给ContinueWith())。

【讨论】:

  • 从未想过要使用 AllAsync() 函数。似乎符合要求;允许我在没有任何其他解决方法的情况下避免异步/等待。必须检查 SQL 以了解幕后内容并进行一些性能测试。谢谢!
猜你喜欢
  • 2014-02-26
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多