LINQ如何使All方法异步化?

10

你好,我正在寻找一种使所有方法以异步模式运行的方法。实际上,我正在尝试想出如何在LINQ中需要时使用异步的方法。有些LINQ方法也有异步定义,但我不太明白为什么不是所有方法都有异步定义,所以希望有人可以为我解释清楚。

与我尝试使All异步运行相关

Version 2

 async Task<bool> IHrtbProfileValidator.ValidateHrtb(UserHrtbProfileDTO dto_Hrtb)
        {
            var x = _validator.All(async (ck) => await ck.ValidateHrtb(dto_Hrtb));
            return x;
        }

第二版

var x = _validator.All((ck) => await ck.ValidateHrtb(dto_Hrtb));

第三版

  var x = _validator.All(async (ck) => await ck.ValidateHrtb(dto_Hrtb).Result);

这是我尝试过的:

我的想法是,我有一个IValidator接口,多个验证器类都实现了它,每个类负责自己的验证相关逻辑。在MainValidator类中,我只是想调用All方法来验证一组IValidator。

谢谢大家。


1
LINQ没有任何异步方法。它是一种查询语言,实际上并不执行查询。您可能将其与Entity Framework及其异步方法(例如ToListAsync)混淆了。 - Panagiotis Kanavos
1个回答

9
你不能将All方法本身变成异步的,但你可以做一个Select,等待结果,然后将该结果传递给All
async Task<bool> IHrtbProfileValidator.ValidateHrtb(UserHrtbProfileDTO dto_Hrtb)
{
    IEnumerable<Task<bool>> items = _validator.Select(ck => ck.ValidateHrtb(dto_Hrtb));
    bool[] results = await Task.WhenAll(items);
    var x = results.All(item => item);
    return x;
}

另一个选择是您可以创建自己的AllAsync扩展方法,该方法适用于任务作为源或谓词。
public static class ExtensionMethods
{
    // This is for async predicates with either a sync or async source.
    // This is the only one you need for your example
    public static async Task<bool> AllAsync<TSource>(this IEnumerable<TSource> source, Func<TSource, Task<bool>> predicate)
    {
        if (source == null)
            throw new ArgumentNullException(nameof(source));
        if (predicate == null)
            throw new ArgumentNullException(nameof(predicate));
        foreach (var item in source)
        {
            var result = await predicate(item);
            if (!result)
                return false;
        }
        return true;
    }

    // This is for synchronous predicates with an async source.
    public static async Task<bool> AllAsync<TSource>(this IEnumerable<Task<TSource>> source, Func<TSource, bool> predicate)
    {
        if (source == null)
            throw new ArgumentNullException(nameof(source));
        if (predicate == null)
            throw new ArgumentNullException(nameof(predicate));
        foreach (var item in source)
        {
            var awaitedItem = await item;
            if (!predicate(awaitedItem))
                return false;
        }
        return true;
    }
}

你可以这样做:
async Task<bool> IHrtbProfileValidator.ValidateHrtb(UserHrtbProfileDTO dto_Hrtb)
{
    var x = await _validator.AllAsync((ck) => ck.ValidateHrtb(dto_Hrtb));
    return x;
}

1
需要指出的是,在第一个例子中执行顺序不能得到保证,但使用扩展方法的方式将按照源项目枚举的顺序逐个执行比较。 - natenho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接