等待异步谓词列表,但先丢弃

Veg*_*gar 6 .net c# linq enumeration async-await

想象一下以下课程:

public class Checker
{
   public async Task<bool> Check() { ... }
}
Run Code Online (Sandbox Code Playgroud)

现在,想象一下这个类的实例列表:

IEnumerable<Checker> checkers = ...
Run Code Online (Sandbox Code Playgroud)

现在我想控制每个实例都会返回true:

checkers.All(c => c.Check());
Run Code Online (Sandbox Code Playgroud)

现在,这不会编译,因为Check()返回Task<bool>不是a bool.

所以我的问题是:我怎样才能最好地列举检查器列表?如果检查器返回,我怎样才能快速进行枚举false?(我认为All( )已经存在的事情)

Ste*_*ary 10

"异步序列"总是会引起一些混乱.例如,目前尚不清楚您所需的语义是否为:

  1. 同时启动所有检查,并在完成后对其进行评估.
  2. 一次启动一个检查,按顺序评估它们.

还有第三种可能性(同时启动所有检查,并按顺序评估它们),但在这种情况下这将是愚蠢的.

我建议将Rx用于异步序列.它为您提供了很多选择,而且有点难以学习,但它也会迫使您思考您想要的内容.

以下代码将同时启动所有检查并在完成时对其进行评估:

IObservable<bool> result = checkers.ToObservable()
    .SelectMany(c => c.Check()).All(b => b);
Run Code Online (Sandbox Code Playgroud)

它首先将棋子序列转换为可观察者,然后调用Check它们,并检查它们是否全部true.第一个Checkfalse值完成将导致result产生一个false值.

相反,以下代码将一次启动一个检查,按顺序评估它们:

IObservable<bool> result = checkers.Select(c => c.Check().ToObservable())
    .Concat().All(b => b);
Run Code Online (Sandbox Code Playgroud)

它首先将检查器序列转换为可观察序列,然后连接这些序列(一次启动一个序列).

如果你不想使用observables并且不想混淆订阅,你可以await直接使用它们.例如,呼叫Check所有检查员并在完成后评估结果:

bool all = await checkers.ToObservable().SelectMany(c => c.Check()).All(b => b);
Run Code Online (Sandbox Code Playgroud)

  • RX是几个中的一个'我明白这对我有好处,但我的大脑会对我有害.特别是如果你在它上面添加RxUI ;-) (2认同)

dca*_*tro 5

如果检查器返回false,我怎样才能快速枚举枚举?

这将按完成顺序检查任务的结果.因此,如果第一个任务#5完成,并返回false,则该方法立即返回false,而不管其他任务如何.永远不会检查较慢的任务(#1,#2等).

public static async Task<bool> AllAsync(this IEnumerable<Task<bool>> source)
{
    var tasks = source.ToList();

    while(tasks.Count != 0)
    {
        var finishedTask = await Task.WhenAny(tasks);

        if(! finishedTask.Result)
            return false;

        tasks.Remove(finishedTask);
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

用法:

bool result = await checkers.Select(c => c.Check())
                            .AllAsync();
Run Code Online (Sandbox Code Playgroud)