You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Note that as part of that expansion, the compiler introduced several awaits not visible in the original source code (which is part of why a developer annotates the foreach as foreach await). This introduces an issue, in that a developer now no longer has explicit syntactic control for that await operation, which means that there’s nowhere for a developer to append ConfigureAwait(false) if they want to prevent the await from grabbing the current context and scheduling the continuation back to it. Our guidelines are that library code by default should use ConfigureAwait(false) on every await, so the lack of that here is problematic for library authors.
Because foreach await is able to bind by pattern, this ConfiguredAsyncEnumerable<T> can be foreach await’d, and the previously shown expansion will now how each of the awaits operating on a ConfiguredValueTaskAwaitable<T> or ConfiguredValueTaskAwaitable instead of a ValueTask<T> or ValueTask.
Open issues:
Do we want this?foreach await is just syntactic sugar for something a developer could otherwise write. However, it’s really useful syntactic sugar, and forcing a developer that wants to iterate through an async enumerable in a library to expand it out manually seems wrong.
Extension method type name and namespace. Presumably AsyncEnumerable is a nice name for a LINQ implementation to use. Do we want to claim it for this? But presumably it should also live in the same namespace as IAsyncEnumerable<T>, so that it’s always available when using that interface.
The text was updated successfully, but these errors were encountered:
As an alternative to the static ConfigureAwait() method (which I don't like as a concept), could you handle this the same way you are handling passing the cancellation token, by pushing it outside the scope of IAsyncEnumerable?
That way, each implementation of IAsyncEnumerable can provide its ConfigureAwait() method.
Also, in the future, if you find a better solution, it will be easier to introduce then...
As an alternative to the static ConfigureAwait() method (which I don't like as a concept), could you handle this the same way you are handling passing the cancellation token, by pushing it outside the scope of IAsyncEnumerable?
I'm not entirely sure what you mean, as the ConfigureAwait is entirely outside the scope of the IAsyncEnumerable, more so than with CancellationToken. ValueTask, which is returned by MoveNextAsync and DisposeAsync, supports ConfigureAwait already, so this extension method on IAsyncEnumerable is just a way to get the compiler's pattern-matching for await foreach to pass that ConfigureAwait call on to each ValueTask it awaits. It's implemented entirely on top of everything else, without any hooks or internals access or any such things needed.
Related to https://github.com/dotnet/corefx/issues/32640.
Background
With the addition of
IAsyncEnumerable<T>
, developers will be able to write asynchronous foreach loops, e.g.This loop expands by the compiler into the equivalent of:
Note that as part of that expansion, the compiler introduced several
await
s not visible in the original source code (which is part of why a developer annotates theforeach
asforeach await
). This introduces an issue, in that a developer now no longer has explicit syntactic control for thatawait
operation, which means that there’s nowhere for a developer to appendConfigureAwait(false)
if they want to prevent theawait
from grabbing the current context and scheduling the continuation back to it. Our guidelines are that library code by default should useConfigureAwait(false)
on everyawait
, so the lack of that here is problematic for library authors.Proposal
Allow a developer to write:
This would be achieved with an extension method as follows:
Because
foreach await
is able to bind by pattern, thisConfiguredAsyncEnumerable<T>
can beforeach await
’d, and the previously shown expansion will now how each of theawait
s operating on aConfiguredValueTaskAwaitable<T>
orConfiguredValueTaskAwaitable
instead of aValueTask<T>
orValueTask
.Open issues:
foreach await
is just syntactic sugar for something a developer could otherwise write. However, it’s really useful syntactic sugar, and forcing a developer that wants to iterate through an async enumerable in a library to expand it out manually seems wrong.AsyncEnumerable
is a nice name for a LINQ implementation to use. Do we want to claim it for this? But presumably it should also live in the same namespace asIAsyncEnumerable<T>
, so that it’s always available when using that interface.The text was updated successfully, but these errors were encountered: