I working with AsyncEnumerables to read a bunch of files into my C# application (.NET 6) and want to add an option to cancel reading. However I'm confused by the behaviour of ToArrayAsync when provided with a cancellationToken.
I tried to break it down to this snippet:
var enumerable = Enumerable.Range(1, 10)
    .ToAsyncEnumerable()
    .SelectAwait(async x => { await Task.Delay(1000); return x; });
var cts = new CancellationTokenSource();
var resultTask = enumerable.ToArrayAsync(cts.Token);
cts.Cancel();
var z = await resultTask;
From my understanding SelectAwait and ToArrayAsync should evaluate one entry after another (which is supported by timing it). I'd expect ToArrayAsync to check the provided token after everyone of those steps. I tried looking up the source for it and think it boils down to this bit, seemingly also supporting my assumption:
public ValueTask<bool> MoveNextAsync()
{
    _cancellationToken.ThrowIfCancellationRequested();
    return _source.MoveNextAsync(); // REVIEW: Signal cancellation through task or synchronously?
}
However in practice ToArrayAsync fully evaluates all entries of the enumerable (taking the full 10 seconds) and returns without a cancellation-exception. Calling ToArrayAsync with an already cancelled token immediately throws, so presumably it only checks at the very start of its execution?
I know I can work around that by using SelectAwaitWithCancellation and checking to token inside its lambda, but I'm unsure about my understanding of ToArrayAsync and AsyncEnumerables in general, so I'd be happy about clarification about how it works and what's the design thinking behind it.