Asynchronous sequences can always cause some confusion. For example, it is not clear if your desired semantics are:
- Start all checks at the same time and evaluate them as they are completed.
- Start checks one at a time, evaluating them in order of priority.
There is a third possibility (first run all the checks and evaluate them in sequence), but that would be stupid in this scenario.
I recommend using Rx for asynchronous sequences. It gives you a lot of opportunities, and it's a little hard to learn, but it also makes you think about exactly what you want.
The following code runs all the checks at the same time and evaluates them as they are completed:
IObservable<bool> result = checkers.ToObservable() .SelectMany(c => c.Check()).All(b => b);
First, it converts the sequence of checkers into observable, calls all Checks on them and checks if they are all true . The first Check , which ends with false , calls result to create false .
In contrast, the following code runs checks one at a time, evaluating them in sequence:
IObservable<bool> result = checkers.Select(c => c.Check().ToObservable()) .Concat().All(b => b);
First, it converts the sequence of checkers into a sequence of observables, and then combines these sequences (which start them one at a time).
If you donโt want to use observational data a lot and donโt want to contact subscriptions, you can directly await them. For example, to call Check on all checkers and evaluate the results as they are completed:
bool all = await checkers.ToObservable().SelectMany(c => c.Check()).All(b => b);