Await list of async predicates, but drop out on first false

后端 未结 6 1101
孤街浪徒
孤街浪徒 2021-01-12 21:20

Imagine the following class:

public class Checker
{
   public async Task Check() { ... }
}

Now, imagine a list of instances of

6条回答
  •  耶瑟儿~
    2021-01-12 21:41

    "Asynchronous sequences" can always cause some confusion. For example, it's not clear whether your desired semantics are:

    1. Start all checks simultaneously, and evaluate them as they complete.
    2. Start the checks one at a time, evaluating them in sequence order.

    There's a third possibility (start all checks simultaneously, and evaluate them in sequence order), but that would be silly in this scenario.

    I recommend using Rx for asynchronous sequences. It gives you a lot of options, and it a bit hard to learn, but it also forces you to think about exactly what you want.

    The following code will start all checks simultaneously and evaluate them as they complete:

    IObservable result = checkers.ToObservable()
        .SelectMany(c => c.Check()).All(b => b);
    

    It first converts the sequence of checkers to an observable, calls Check on them all, and checks whether they are all true. The first Check that completes with a false value will cause result to produce a false value.

    In contrast, the following code will start the checks one at a time, evaluating them in sequence order:

    IObservable result = checkers.Select(c => c.Check().ToObservable())
        .Concat().All(b => b);
    

    It first converts the sequence of checkers to a sequence of observables, and then concatenates those sequences (which starts them one at a time).

    If you do not wish to use observables much and don't want to mess with subscriptions, you can await them directly. E.g., to call Check on all checkers and evaluate the results as they complete:

    bool all = await checkers.ToObservable().SelectMany(c => c.Check()).All(b => b);
    

提交回复
热议问题