New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: IAsyncEnumerable<T>.WithCancellation extension method #28105
Comments
|
There were supposed to be instance methods on the struct as well mirroring the extension methods. I've fixed that above.
See the "Note that the..." paragraph at the end.
It's for ConfigureAwait, so that MoveNextAsync returns the awaitable that's aware of the configured context settings. |
Thanks.
I was assuming that pattern-based We can raise the question in LDM. |
I assume that I can see three alternatives:
All three alternatives sound mostly reasonable to me, so I'm not sure which one of them would be best. |
The token doesn't actually impact the behavior of the awaits, though. |
@stephentoub I think that from a certain point of view, it does, especially if it's decided that compiler-generated async enumerable will check the You could claim (and I think you are) that |
If the CancellationToken were actually configuring the await, it would, for example, cancel the await operation even if the awaited thing hasn't completed yet. That's always the behavior we've talked about when considering whether to have a ConfigureAwait overload that accepted a CancellationToken, and that's very much not what happens here. I want to avoid that connotation. |
@stephentoub Yeah, that does make sense. Thanks for the explanation. |
Looks good. I ran into the exact problem when building various aggregation functions for LINQ to IAsyncEnumerable. However, I wonder if it would be better for these to live in some I see this has been brought up before when introducing It may not matter all that much, given that VS offers to include the namespace when trying to use an extension method (and |
As mentioned by @yyjdelete here, the
|
@jcouv, not sure how I missed that in the ldm discussion, but I don't think that can be the answer. How does ConfigureAwait work in that model? |
Background
Per recent design revisions,
IAsyncEnumerable<T>.GetAsyncEnumerator
will now accept aCancellationToken
. To get a cancellation token into theGetAsyncEnumerator
call, code can useGetAsyncEnumerator
explicitly, e.g.To use
await foreach
, as there’s no language-provided facility for passing aCancellationToken
into the compiler-generatedGetAsyncEnumerator
call, to get aCancellationToken
in we need to take advantage of the pattern-matching supportawait foreach
supplies. By returning a struct that exposes the right pattern, we can smuggle aCancellationToken
in, stored in that struct, such that when the compiler-generated code invokes that struct’sGetAsyncEnumerator()
, it in turn callsGetAsyncEnumerator(_cancellationToken)
on the underlying enumerable.To make that simple, we should add a
WithCancellation
extension method onIAsyncEnumerable<T>
that accepts theCancellationToken
, allowing you to write:with that generating the equivalent of:
However, we also need to deal with the ability to
ConfigureAwait(false)
an enumerable. We’ve already added theConfigureAwait(bool)
extension method forIAsyncEnumerable<T>
, and we need to be able to allow developers to use both it andWithCancellation
. Since both of these would return structs that by design do not implementIAsyncEnumerable<T>
, we need another mechanism to allow chaining them, e.g.Proposal
As part of adding the async-related interfaces, we also added a
ConfigureAwait
extension method and a newConfiguredAsyncEnumerable
struct type. We replace those with a slightly updated version:This let’s you write:
It of course also lets you write something a bit non-sensical, like:
and in such a case we would just use the last value specified, e.g. this would end up being equivalent to:
Note that the
GetAsyncEnumerator()
on the struct is defined to be parameterless (this assumes the compiler's pattern-matching support allows that... if not, it'll be defined to take a token as well). Since this struct is only ever meant to be used via the provided extension methods with theawait foreach
construct, there’s little use for also accepting aCancellationToken
intoGetAsyncEnumerator()
, and allowing that would just be confusing, as that argument will be ignored by the implementation.cc: @jcouv, @MadsTorgersen, @terrajobst, @bartonjs
The text was updated successfully, but these errors were encountered: