public void Initialize(Type type, JsonSerializerOptions options) { JsonClassInfo = options.GetOrAddClass(type); if (JsonClassInfo.ClassType == ClassType.Value || JsonClassInfo.ClassType == ClassType.Enumerable || JsonClassInfo.ClassType == ClassType.Dictionary) { JsonPropertyInfo = JsonClassInfo.GetPolicyProperty(); } else if (JsonClassInfo.ClassType == ClassType.ImmutableDictionary) { JsonPropertyInfo = JsonClassInfo.GetPolicyProperty(); IsImmutableDictionary = true; } }
private static void WriteCore(ArrayBufferWriter <byte> output, object value, Type type, JsonSerializerOptions options) { Debug.Assert(type != null || value == null); var writerState = new JsonWriterState(options.WriterOptions); var writer = new Utf8JsonWriter(output, writerState); if (value == null) { writer.WriteNullValue(); } else { // We treat typeof(object) special and allow polymorphic behavior. if (type == typeof(object)) { type = value.GetType(); } WriteStack state = default; JsonClassInfo classInfo = options.GetOrAddClass(type); state.Current.JsonClassInfo = classInfo; state.Current.CurrentValue = value; if (classInfo.ClassType != ClassType.Object) { state.Current.JsonPropertyInfo = classInfo.GetPolicyProperty(); } Write(ref writer, -1, options, ref state); } writer.Flush(isFinalBlock: true); }
public void InitializeJsonPropertyInfo() { if (JsonClassInfo.ClassType == ClassType.Value || JsonClassInfo.ClassType == ClassType.Enumerable || JsonClassInfo.ClassType == ClassType.Dictionary) { JsonPropertyInfo = JsonClassInfo.GetPolicyProperty(); } }
private static async Task WriteAsyncInternal(object value, Type type, Stream utf8Stream, JsonSerializerOptions options, CancellationToken cancellationToken) { if (options == null) { options = s_defaultSettings; } var writerState = new JsonWriterState(options.WriterOptions); using (var bufferWriter = new ArrayBufferWriter <byte>(options.EffectiveBufferSize)) { if (value == null) { WriteNull(ref writerState, bufferWriter); #if BUILDING_INBOX_LIBRARY await utf8Stream.WriteAsync(bufferWriter.WrittenMemory, cancellationToken).ConfigureAwait(false); #else // todo: stackalloc? await utf8Stream.WriteAsync(bufferWriter.WrittenMemory.ToArray(), 0, bufferWriter.WrittenMemory.Length, cancellationToken).ConfigureAwait(false); #endif return; } if (type == null) { type = value.GetType(); } JsonClassInfo classInfo = options.GetOrAddClass(type); WriteObjectState current = default; current.ClassInfo = classInfo; current.CurrentValue = value; if (classInfo.ClassType != ClassType.Object) { current.PropertyInfo = classInfo.GetPolicyProperty(); } List <WriteObjectState> previous = null; int arrayIndex = 0; bool isFinalBlock; int flushThreshold; do { flushThreshold = (int)(bufferWriter.Capacity * .9); //todo: determine best value here isFinalBlock = Write(ref writerState, bufferWriter, flushThreshold, options, ref current, ref previous, ref arrayIndex); #if BUILDING_INBOX_LIBRARY await utf8Stream.WriteAsync(bufferWriter.WrittenMemory, cancellationToken).ConfigureAwait(false); #else // todo: stackalloc? await utf8Stream.WriteAsync(bufferWriter.WrittenMemory.ToArray(), 0, bufferWriter.WrittenMemory.Length, cancellationToken).ConfigureAwait(false); #endif bufferWriter.Clear(); } while (!isFinalBlock); } // todo: do we want to call FlushAsync here (or above)? It seems like leaving it to the caller would be better. //await stream.FlushAsync(cancellationToken).ConfigureAwait(false); }
private static object Read( Utf8JsonReader reader, Type returnType, JsonSerializerOptions options) { if (options == null) { options = s_defaultSettings; } List <ReadObjectState> previous = null; int arrayIndex = 0; ReadObjectState current = default; JsonClassInfo classInfo = options.GetOrAddClass(returnType); current.ClassInfo = classInfo; if (classInfo.ClassType != ClassType.Object) { current.PropertyInfo = classInfo.GetPolicyProperty(); } Read(returnType, options, ref reader, ref current, ref previous, ref arrayIndex); return(current.ReturnValue); }
private static bool HandleEnumerable( JsonClassInfo elementClassInfo, JsonSerializerOptions options, ref Utf8JsonWriter writer, ref WriteStack state) { Debug.Assert(state.Current.JsonPropertyInfo.ClassType == ClassType.Enumerable); JsonPropertyInfo propertyInfo = state.Current.JsonPropertyInfo; if (state.Current.Enumerator == null) { if (propertyInfo._name == null) { writer.WriteStartArray(); } else { writer.WriteStartArray(propertyInfo._name); } IEnumerable enumerable = (IEnumerable)propertyInfo.GetValueAsObject(state.Current.CurrentValue, options); if (enumerable != null) { state.Current.Enumerator = enumerable.GetEnumerator(); } } if (state.Current.Enumerator != null && state.Current.Enumerator.MoveNext()) { if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.GetPolicyProperty().WriteEnumerable(options, ref state.Current, ref writer); } else { // An object or another enumerator requires a new stack frame JsonClassInfo nextClassInfo = propertyInfo.ElementClassInfo; object nextValue = state.Current.Enumerator.Current; state.Push(nextClassInfo, nextValue); } return(false); } // We are done enumerating. writer.WriteEndArray(); if (state.Current.PopStackOnEndArray) { state.Pop(); } else { state.Current.EndArray(); } return(true); }
internal void Initialize(Type type, JsonSerializerOptions options) { JsonClassInfo = options.GetOrAddClass(type); if (JsonClassInfo.ClassType == ClassType.Value || JsonClassInfo.ClassType == ClassType.Enumerable || JsonClassInfo.ClassType == ClassType.Dictionary) { JsonPropertyInfo = JsonClassInfo.GetPolicyProperty(); } }
private static async Task WriteAsyncCore(object value, Type type, Stream utf8Json, JsonSerializerOptions options, CancellationToken cancellationToken) { if (options == null) { options = s_defaultSettings; } var writerState = new JsonWriterState(options.WriterOptions); using (var bufferWriter = new ArrayBufferWriter <byte>(options.EffectiveBufferSize)) { if (value == null) { WriteNull(ref writerState, bufferWriter); #if BUILDING_INBOX_LIBRARY await utf8Json.WriteAsync(bufferWriter.WrittenMemory, cancellationToken).ConfigureAwait(false); #else // todo: stackalloc or pool here? await utf8Json.WriteAsync(bufferWriter.WrittenMemory.ToArray(), 0, bufferWriter.WrittenMemory.Length, cancellationToken).ConfigureAwait(false); #endif return; } if (type == null) { type = value.GetType(); } JsonClassInfo classInfo = options.GetOrAddClass(type); WriteStack state = default; state.Current.JsonClassInfo = classInfo; state.Current.CurrentValue = value; if (classInfo.ClassType != ClassType.Object) { state.Current.JsonPropertyInfo = classInfo.GetPolicyProperty(); } bool isFinalBlock; int flushThreshold; do { flushThreshold = (int)(bufferWriter.Capacity * .9); //todo: determine best value here isFinalBlock = Write(ref writerState, bufferWriter, flushThreshold, options, ref state); #if BUILDING_INBOX_LIBRARY await utf8Json.WriteAsync(bufferWriter.WrittenMemory, cancellationToken).ConfigureAwait(false); #else // todo: use pool here to avod extra alloc? await utf8Json.WriteAsync(bufferWriter.WrittenMemory.ToArray(), 0, bufferWriter.WrittenMemory.Length, cancellationToken).ConfigureAwait(false); #endif bufferWriter.Clear(); } while (!isFinalBlock); } // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best. }
private static async Task WriteAsyncInternal(object value, Type type, PipeWriter utf8Writer, JsonSerializerOptions options, CancellationToken cancellationToken) { if (options == null) { options = s_defaultSettings; } var writerState = new JsonWriterState(options.WriterOptions); // Allocate the initial buffer. We don't want to use the existing buffer as there may be very few bytes left // and we won't be able to calculate flushThreshold appropriately. Memory <byte> memory = utf8Writer.GetMemory(options.EffectiveBufferSize); if (value == null) { WriteNull(ref writerState, utf8Writer); await utf8Writer.FlushAsync(cancellationToken).ConfigureAwait(false); return; } if (type == null) { type = value.GetType(); } JsonClassInfo classInfo = options.GetOrAddClass(type); WriteObjectState current = default; current.ClassInfo = classInfo; current.CurrentValue = value; if (classInfo.ClassType != ClassType.Object) { current.PropertyInfo = classInfo.GetPolicyProperty(); } List <WriteObjectState> previous = null; int arrayIndex = 0; bool isFinalBlock; // For Pipes there is not a way to get current buffer total size, so we just use the initial memory size. int flushThreshold = (int)(memory.Length * .9); //todo: determine best value here (extensible?) do { isFinalBlock = Write(ref writerState, utf8Writer, flushThreshold, options, ref current, ref previous, ref arrayIndex); await utf8Writer.FlushAsync(cancellationToken).ConfigureAwait(false); } while (!isFinalBlock); }
private static byte[] WriteInternal(object value, Type type, JsonSerializerOptions options) { if (options == null) { options = s_defaultSettings; } byte[] result; var state = new JsonWriterState(options.WriterOptions); using (var output = new ArrayBufferWriter <byte>(options.EffectiveBufferSize)) { var writer = new Utf8JsonWriter(output, state); if (value == null) { writer.WriteNullValue(); } else { if (type == null) { type = value.GetType(); } WriteObjectState current = default; JsonClassInfo classInfo = options.GetOrAddClass(type); current.ClassInfo = classInfo; current.CurrentValue = value; if (classInfo.ClassType != ClassType.Object) { current.PropertyInfo = classInfo.GetPolicyProperty(); } List <WriteObjectState> previous = null; int arrayIndex = 0; Write(ref writer, -1, options, ref current, ref previous, ref arrayIndex); } writer.Flush(isFinalBlock: true); result = output.WrittenMemory.ToArray(); } return(result); }
internal JsonPropertyInfo GetJsonPropertyInfoFromClassInfo(JsonClassInfo classInfo, JsonSerializerOptions options) { if (classInfo.ClassType != ClassType.Object) { return(classInfo.GetPolicyProperty()); } Type objectType = classInfo.Type; if (!_objectJsonProperties.TryGetValue(objectType, out JsonPropertyInfo propertyInfo)) { propertyInfo = JsonClassInfo.CreateProperty(objectType, objectType, null, typeof(object), options); _objectJsonProperties[objectType] = propertyInfo; } return(propertyInfo); }
private static async Task <T> ReadAsync <T>(PipeReader utf8Reader, Type returnType, JsonSerializerOptions options = null, CancellationToken cancellationToken = default) { if (options == null) { options = s_defaultSettings; } ReadObjectState current = default; JsonClassInfo classInfo = options.GetOrAddClass(returnType); current.ClassInfo = classInfo; if (classInfo.ClassType != ClassType.Object) { current.PropertyInfo = classInfo.GetPolicyProperty(); } var readerState = new JsonReaderState(options: options.ReaderOptions); List <ReadObjectState> previous = null; int arrayIndex = 0; ReadResult result; do { result = await utf8Reader.ReadAsync(cancellationToken).ConfigureAwait(false); ReadOnlySequence <byte> buffer = result.Buffer; Read( ref readerState, returnType, result.IsCompleted, buffer, options, ref current, ref previous, ref arrayIndex); utf8Reader.AdvanceTo(buffer.GetPosition(readerState.BytesConsumed), buffer.End); } while (!result.IsCompleted); return((T)current.ReturnValue); }
private static object ReadCore( Type returnType, JsonSerializerOptions options, ref Utf8JsonReader reader) { if (options == null) { options = s_defaultSettings; } ReadStack state = default; JsonClassInfo classInfo = options.GetOrAddClass(returnType); state.Current.JsonClassInfo = classInfo; if (classInfo.ClassType != ClassType.Object) { state.Current.JsonPropertyInfo = classInfo.GetPolicyProperty(); } ReadCore(options, ref reader, ref state); return(state.Current.ReturnValue); }
private static bool HandleDictionary( JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (!jsonPropertyInfo.ShouldSerialize) { // Ignore writing this property. return(true); } if (state.Current.Enumerator == null) { // Verify that the Dictionary can be serialized by having <string> as first generic argument. Type[] args = jsonPropertyInfo.RuntimePropertyType.GetGenericArguments(); if (args.Length == 0 || args[0].UnderlyingSystemType != typeof(string)) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, state.PropertyPath); } IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue); if (enumerable == null) { // Write a null object or enumerable. state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, writeNull: true); return(true); } state.Current.Enumerator = enumerable.GetEnumerator(); state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer); } if (state.Current.Enumerator.MoveNext()) { // Check for polymorphism. if (elementClassInfo.ClassType == ClassType.Unknown) { object currentValue = ((IDictionaryEnumerator)state.Current.Enumerator).Entry.Value; GetRuntimeClassInfo(currentValue, ref elementClassInfo, options); } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.GetPolicyProperty().WriteDictionary(options, ref state.Current, writer); } else if (state.Current.Enumerator.Current == null) { writer.WriteNull(jsonPropertyInfo.Name); } else { // An object or another enumerator requires a new stack frame. var enumerator = (IDictionaryEnumerator)state.Current.Enumerator; object value = enumerator.Value; state.Push(elementClassInfo, value); state.Current.KeyName = (string)enumerator.Key; } return(false); } // We are done enumerating. writer.WriteEndObject(); if (state.Current.PopStackOnEnd) { state.Pop(); } else { state.Current.EndDictionary(); } return(true); }
private static bool HandleEnumerable( JsonClassInfo elementClassInfo, JsonSerializerOptions options, ref Utf8JsonWriter writer, ref WriteStack state) { Debug.Assert(state.Current.JsonPropertyInfo.ClassType == ClassType.Enumerable); JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (state.Current.Enumerator == null) { if (jsonPropertyInfo._name == null) { writer.WriteStartArray(); } else { writer.WriteStartArray(jsonPropertyInfo._name); } IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue, options); if (enumerable != null) { state.Current.Enumerator = enumerable.GetEnumerator(); } } if (state.Current.Enumerator != null && state.Current.Enumerator.MoveNext()) { // If the enumerator contains typeof(object), get the run-time type if (elementClassInfo.ClassType == ClassType.Object && jsonPropertyInfo.ElementClassInfo.Type == typeof(object)) { object currentValue = state.Current.Enumerator.Current; if (currentValue != null) { Type runtimeType = currentValue.GetType(); // Ignore object() instances since they are handled as an empty object. if (runtimeType != typeof(object)) { elementClassInfo = options.GetOrAddClass(runtimeType); } } } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.GetPolicyProperty().WriteEnumerable(options, ref state.Current, ref writer); } else if (state.Current.Enumerator.Current == null) { // Write a null object or enumerable. writer.WriteNullValue(); } else { // An object or another enumerator requires a new stack frame. object nextValue = state.Current.Enumerator.Current; state.Push(elementClassInfo, nextValue); } return(false); } // We are done enumerating. writer.WriteEndArray(); if (state.Current.PopStackOnEndArray) { state.Pop(); } else { state.Current.EndArray(); } return(true); }
private static bool HandleDictionary( JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (state.Current.Enumerator == null) { IEnumerable enumerable; enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue); if (enumerable == null) { // Write a null object or enumerable. state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, writeNull: true); return(true); } state.Current.Enumerator = enumerable.GetEnumerator(); state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer); } if (state.Current.Enumerator.MoveNext()) { // Handle DataExtension. if (ReferenceEquals(jsonPropertyInfo, state.Current.JsonClassInfo.DataExtensionProperty)) { WriteExtensionData(writer, ref state.Current); } else { // Check for polymorphism. if (elementClassInfo.ClassType == ClassType.Unknown) { object currentValue = ((IDictionaryEnumerator)state.Current.Enumerator).Entry.Value; GetRuntimeClassInfo(currentValue, ref elementClassInfo, options); } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.GetPolicyProperty().WriteDictionary(ref state.Current, writer); } else if (state.Current.Enumerator.Current == null) { writer.WriteNull(jsonPropertyInfo.Name); } else { // An object or another enumerator requires a new stack frame. var enumerator = (IDictionaryEnumerator)state.Current.Enumerator; object value = enumerator.Value; state.Push(elementClassInfo, value); state.Current.KeyName = (string)enumerator.Key; } } return(false); } // We are done enumerating. writer.WriteEndObject(); if (state.Current.PopStackOnEnd) { state.Pop(); } else { state.Current.EndDictionary(); } return(true); }
private static async ValueTask <TValue> ReadAsync <TValue>(Stream utf8Json, Type returnType, JsonSerializerOptions options = null, CancellationToken cancellationToken = default) { if (options == null) { options = s_defaultSettings; } ReadObjectState current = default; JsonClassInfo classInfo = options.GetOrAddClass(returnType); current.ClassInfo = classInfo; if (classInfo.ClassType != ClassType.Object) { current.PropertyInfo = classInfo.GetPolicyProperty(); } var readerState = new JsonReaderState(options: options.ReaderOptions); List <ReadObjectState> previous = null; int arrayIndex = 0; int bytesRemaining = 0; int bytesRead; // todo: switch to ArrayBuffer implementation to handle the allocs? byte[] buffer = ArrayPool <byte> .Shared.Rent(options.EffectiveBufferSize); int bufferSize = buffer.Length; bool isFinalBlock; try { do { int bytesToRead = bufferSize - bytesRemaining; bytesRead = await utf8Json.ReadAsync(buffer, bytesRemaining, bytesToRead, cancellationToken).ConfigureAwait(false); int deserializeBufferSize = bytesRemaining + bytesRead; isFinalBlock = (bytesRead == 0); ReadCore( ref readerState, isFinalBlock, buffer, deserializeBufferSize, options, ref current, ref previous, ref arrayIndex); if (isFinalBlock) { return((TValue)current.ReturnValue); } // We have to shift or expand the buffer because there wasn't enough data to complete deserialization. int bytesConsumed = (int)readerState.BytesConsumed; bytesRemaining = deserializeBufferSize - bytesConsumed; if (bytesConsumed <= (bufferSize / 2)) { // We have less than half the buffer available, double the buffer size. bufferSize = (bufferSize < HalfMaxValue) ? bufferSize * 2 : int.MaxValue; byte[] dest = ArrayPool <byte> .Shared.Rent(bufferSize); bufferSize = dest.Length; if (bytesRemaining > 0) { // Copy the unprocessed data to the new buffer while shifting the processed bytes. Buffer.BlockCopy(buffer, bytesConsumed, dest, 0, bytesRemaining); } ArrayPool <byte> .Shared.Return(buffer, clearArray : true); buffer = dest; } else if (bytesRemaining > 0) { // Shift the processed bytes to the beginning of buffer to make more room. Buffer.BlockCopy(buffer, bytesConsumed, buffer, 0, bytesRemaining); } } while (!isFinalBlock); } finally { ArrayPool <byte> .Shared.Return(buffer, clearArray : true); } throw new InvalidOperationException("todo"); }
private static async ValueTask <TValue> ReadAsync <TValue>(Stream utf8Json, Type returnType, JsonSerializerOptions options = null, CancellationToken cancellationToken = default) { options ??= s_defaultSettings; ReadStack state = default; JsonClassInfo classInfo = options.GetOrAddClass(returnType); state.Current.JsonClassInfo = classInfo; if (classInfo.ClassType != ClassType.Object) { state.Current.JsonPropertyInfo = classInfo.GetPolicyProperty(); } var readerState = new JsonReaderState(options.ReaderOptions); // todo: switch to ArrayBuffer implementation to handle and simplify the allocs? byte[] buffer = ArrayPool <byte> .Shared.Rent(options.EffectiveBufferSize); int bytesInBuffer = 0; long totalBytesRead = 0; int clearMax = 0; try { while (true) { // Read from the stream until either our buffer is filled or we hit EOF. // Calling ReadCore is relatively expensive, so we minimize the number of times // we need to call it. bool isFinalBlock = false; while (true) { int bytesRead = await utf8Json.ReadAsync( #if BUILDING_INBOX_LIBRARY buffer.AsMemory(bytesInBuffer), #else buffer, bytesInBuffer, buffer.Length - bytesInBuffer, #endif cancellationToken).ConfigureAwait(false); if (bytesRead == 0) { isFinalBlock = true; break; } totalBytesRead += bytesRead; bytesInBuffer += bytesRead; if (bytesInBuffer == buffer.Length) { break; } } if (bytesInBuffer > clearMax) { clearMax = bytesInBuffer; } // Process the data available ReadCore( ref readerState, isFinalBlock, new Span <byte>(buffer, 0, bytesInBuffer), options, ref state); Debug.Assert(readerState.BytesConsumed <= bytesInBuffer); int bytesConsumed = (int)readerState.BytesConsumed; bytesInBuffer -= bytesConsumed; if (isFinalBlock) { break; } // Check if we need to shift or expand the buffer because there wasn't enough data to complete deserialization. if ((uint)bytesInBuffer > ((uint)buffer.Length / 2)) { // We have less than half the buffer available, double the buffer size. byte[] dest = ArrayPool <byte> .Shared.Rent((buffer.Length < (int.MaxValue / 2))?buffer.Length * 2 : int.MaxValue); // Copy the unprocessed data to the new buffer while shifting the processed bytes. Buffer.BlockCopy(buffer, bytesConsumed, dest, 0, bytesInBuffer); new Span <byte>(buffer, 0, clearMax).Clear(); ArrayPool <byte> .Shared.Return(buffer); clearMax = bytesInBuffer; buffer = dest; } else if (bytesInBuffer != 0) { // Shift the processed bytes to the beginning of buffer to make more room. Buffer.BlockCopy(buffer, bytesConsumed, buffer, 0, bytesInBuffer); } } } finally { // Clear only what we used and return the buffer to the pool new Span <byte>(buffer, 0, clearMax).Clear(); ArrayPool <byte> .Shared.Return(buffer); } if (bytesInBuffer != 0) { throw new JsonReaderException( SR.Format(SR.DeserializeDataRemaining, totalBytesRead, bytesInBuffer), readerState); } return((TValue)state.Current.ReturnValue); }
private static bool HandleDictionary( JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { Debug.Assert(state.Current.JsonPropertyInfo.ClassType == ClassType.Dictionary); JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (!jsonPropertyInfo.ShouldSerialize) { // Ignore writing this property. return(true); } if (state.Current.Enumerator == null) { IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue, options); if (enumerable == null) { // Write a null object or enumerable. writer.WriteNull(jsonPropertyInfo.Name); return(true); } state.Current.Enumerator = enumerable.GetEnumerator(); if (jsonPropertyInfo.Name == null) { writer.WriteStartObject(); } else { writer.WriteStartObject(jsonPropertyInfo.Name); } } if (state.Current.Enumerator.MoveNext()) { // Check for polymorphism. if (elementClassInfo.ClassType == ClassType.Unknown) { //todo:test object currentValue = ((IDictionaryEnumerator)(state.Current.Enumerator)).Entry; GetRuntimeClassInfo(currentValue, ref elementClassInfo, options); } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.GetPolicyProperty().WriteDictionary(options, ref state.Current, writer); } else if (state.Current.Enumerator.Current == null) { writer.WriteNull(jsonPropertyInfo.Name); } else { // An object or another enumerator requires a new stack frame. object nextValue = state.Current.Enumerator.Current; state.Push(elementClassInfo, nextValue); } return(false); } // We are done enumerating. writer.WriteEndObject(); state.Current.EndDictionary(); return(true); }
private static bool HandleEnumerable( JsonClassInfo elementClassInfo, JsonSerializerOptions options, ref Utf8JsonWriter writer, ref WriteStack state) { Debug.Assert(state.Current.JsonPropertyInfo.ClassType == ClassType.Enumerable); JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (state.Current.Enumerator == null) { if (jsonPropertyInfo._name == null) { writer.WriteStartArray(); } else { writer.WriteStartArray(jsonPropertyInfo._name); } IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue, options); if (enumerable != null) { state.Current.Enumerator = enumerable.GetEnumerator(); } } if (state.Current.Enumerator != null && state.Current.Enumerator.MoveNext()) { // Check for polymorphism. if (elementClassInfo.ClassType == ClassType.Unknown) { object currentValue = state.Current.Enumerator.Current; GetRuntimeClassInfo(currentValue, ref elementClassInfo, options); } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.GetPolicyProperty().WriteEnumerable(options, ref state.Current, ref writer); } else if (state.Current.Enumerator.Current == null) { // Write a null object or enumerable. writer.WriteNullValue(); } else { // An object or another enumerator requires a new stack frame. object nextValue = state.Current.Enumerator.Current; state.Push(elementClassInfo, nextValue); } return(false); } // We are done enumerating. writer.WriteEndArray(); if (state.Current.PopStackOnEndArray) { state.Pop(); } else { state.Current.EndArray(); } return(true); }