If you're doing networking, there is very useful new stuff in the latest version of C# and .NET,. but it's Spans and Pipelines more than default interfaces.
Async is not new at all, but classes that really leverage it well might be (pipelines again).
Is async streams and "await foreach" just syntactic sugar for things that could still be done beforehand, albeit with more code?
I mean, "slightly more code" - you can say the same about "async ... await" in general, but then it's "insanely more code" and huge potential for error.
Not quite. F# and a few other languages have had this capability for a few years now. Its effectively making the MoveNext() function on the enumerator object an async operation instead of a blocking one. This allows a foreach loop for example to wait until the next object comes without tying up the thread. Useful for things like pulling off a remote message queue, messages off a network, etc where the waiting for the next item in your "foreach" loop involves async/task based operations and you don't want to block the current thread.
nope async streams weren't really possible before without an unnecessary allocation.
i.e. a List<Task<T>> is not the same as an AsyncEnumerable<T>. List<Func<Task<T>>> would be more equivalent, but you needed to have a List<T> which you need to fill beforehand.
Async is not new at all, but classes that really leverage it well might be (pipelines again).