System.Text.Json: Support for IAsyncEnumerable #37981
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is my first pass at support for IAsyncEnumerable in System.Text.Json, which should satisfy issues #1569 and #1570 (except that, as commented in #1570, I don't think the deserialization can actually be asynchronous, because the object graph might have multiple
IAsyncEnumerable
s in it, and each one would need its own pointer into the underlying stream).This is my first time doing any work with C# 8, and also my first time doing any work with the .NET codebase, so I'm fully expecting there to be some things I overlooked, both in style and substance. :-)
My implementation builds upon
IEnumerableDefaultConverter
, which already has logic for reading a JSON array and passing the elements off to a collection that the subclass gets to define.In addition to this, the converter needs to stash an
IAsyncEnumerator
between invocations. In the case of reference types, it can store this directly intoWriteStackFrame
using type covariance. For value types, type covariance isn't an option. So, two specializations of theIAsyncEnumerableOfTConverter
are provided, customizing how theIAsyncEnumerator
is stashed, using a simple wrapper for value types.When deserializing into a field whose type is
IAsyncEnumerable<T>
, some class that implements the interface is needed, and I'm not aware of one built into the framework, so a simpleAsyncEnumerableList
that subclassesList<T>
and adds an implementation ofIAsyncEnumerable<T>
(just synchronous pass-through, since the data is already there) is used.I modeled the way converter objects get created after what I saw for
IEnumerableOfT
, with a factory that I register in sequence before theIEnumerableConverterFactory
, on the assumption that if a class chooses to implement both, it probably would prefer that the async variant be used.Finally, I added a handful of unit tests in new file
IAsyncEnumerableTests.cs
to capture the various wrinkles I could think of.