<PackageReference Include="System.Text.Json" Version="5.0.0-preview.7.20364.11" />

ObjectWithParameterizedConstructorConverter<T>

using System.Buffers; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace System.Text.Json.Serialization.Converters { internal abstract class ObjectWithParameterizedConstructorConverter<T> : ObjectDefaultConverter<T> { internal override bool ConstructorIsParameterized => true; internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value) { object obj; if (state.UseFastPath) { ReadOnlySpan<byte> originalSpan = reader.OriginalSpan; ReadConstructorArguments(ref state, ref reader, options); obj = CreateObject(ref state.Current); if (state.Current.PropertyIndex > 0) { for (int i = 0; i < state.Current.PropertyIndex; i++) { JsonPropertyInfo item = state.Current.CtorArgumentState.FoundProperties[i].Item1; long item2 = state.Current.CtorArgumentState.FoundProperties[i].Item3; byte[] item3 = state.Current.CtorArgumentState.FoundProperties[i].Item4; string item4 = state.Current.CtorArgumentState.FoundProperties[i].Item5; Utf8JsonReader reader2 = new Utf8JsonReader(originalSpan.Slice(checked((int)item2)), true, state.Current.CtorArgumentState.FoundProperties[i].Item2); state.Current.JsonPropertyName = item3; state.Current.JsonPropertyInfo = item; bool flag = item4 != null; if (flag) { state.Current.JsonPropertyNameAsString = item4; JsonSerializer.CreateDataExtensionProperty(obj, item); } ReadPropertyValue(obj, ref state, ref reader2, item, flag); } ArrayPool<(JsonPropertyInfo, JsonReaderState, long, byte[], string)>.Shared.Return(state.Current.CtorArgumentState.FoundProperties, true); } } else { if (state.Current.ObjectState == StackFrameObjectState.None) { state.Current.ObjectState = StackFrameObjectState.StartToken; BeginRead(ref state, ref reader, options); } if (!ReadConstructorArgumentsWithContinuation(ref state, ref reader, options)) { value = default(T); return false; } obj = CreateObject(ref state.Current); if (state.Current.CtorArgumentState.FoundPropertyCount > 0) { for (int j = 0; j < state.Current.CtorArgumentState.FoundPropertyCount; j++) { JsonPropertyInfo item5 = state.Current.CtorArgumentState.FoundPropertiesAsync[j].Item1; object item6 = state.Current.CtorArgumentState.FoundPropertiesAsync[j].Item2; string item7 = state.Current.CtorArgumentState.FoundPropertiesAsync[j].Item3; if (item7 == null) item5.SetExtensionDictionaryAsObject(obj, item6); else { JsonSerializer.CreateDataExtensionProperty(obj, item5); object valueAsObject = item5.GetValueAsObject(obj); IDictionary<string, JsonElement> dictionary = valueAsObject as IDictionary<string, JsonElement>; if (dictionary != null) dictionary[item7] = (JsonElement)item6; else ((IDictionary<string, object>)valueAsObject)[item7] = item6; } } ArrayPool<(JsonPropertyInfo, object, string)>.Shared.Return(state.Current.CtorArgumentState.FoundPropertiesAsync, true); } } if (state.Current.PropertyRefCache != null) state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current); if (state.Current.CtorArgumentState.ParameterRefCache != null) state.Current.JsonClassInfo.UpdateSortedParameterCache(ref state.Current); EndRead(ref state); value = (T)obj; return true; } protected abstract void InitializeConstructorArgumentCaches(ref ReadStack state, JsonSerializerOptions options); protected abstract bool ReadAndCacheConstructorArgument(ref ReadStack state, ref Utf8JsonReader reader, JsonParameterInfo jsonParameterInfo); protected abstract object CreateObject(ref ReadStackFrame frame); [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ReadConstructorArguments(ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options) { BeginRead(ref state, ref reader, options); while (true) { ref reader.ReadWithVerify(); JsonTokenType tokenType = reader.TokenType; if (tokenType == JsonTokenType.EndObject) break; if (TryLookupConstructorParameter(ref state, ref reader, options, out JsonParameterInfo jsonParameterInfo)) { ref reader.ReadWithVerify(); if (!jsonParameterInfo.ShouldDeserialize) { reader.Skip(); state.Current.EndConstructorParameter(); } else { ReadAndCacheConstructorArgument(ref state, ref reader, jsonParameterInfo); state.Current.EndConstructorParameter(); } } else { ReadOnlySpan<byte> propertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options); bool useExtensionProperty; JsonPropertyInfo item = JsonSerializer.LookupProperty(null, propertyName, ref state, out useExtensionProperty, false); if (state.Current.CtorArgumentState.FoundProperties == null) state.Current.CtorArgumentState.FoundProperties = ArrayPool<(JsonPropertyInfo, JsonReaderState, long, byte[], string)>.Shared.Rent(Math.Max(1, state.Current.JsonClassInfo.PropertyCache.Count)); else if (state.Current.PropertyIndex - 1 == state.Current.CtorArgumentState.FoundProperties.Length) { (JsonPropertyInfo, JsonReaderState, long, byte[], string)[] array = ArrayPool<(JsonPropertyInfo, JsonReaderState, long, byte[], string)>.Shared.Rent(state.Current.CtorArgumentState.FoundProperties.Length * 2); state.Current.CtorArgumentState.FoundProperties.CopyTo(array, 0); ArrayPool<(JsonPropertyInfo, JsonReaderState, long, byte[], string)>.Shared.Return(state.Current.CtorArgumentState.FoundProperties, true); state.Current.CtorArgumentState.FoundProperties = array; } state.Current.CtorArgumentState.FoundProperties[state.Current.PropertyIndex - 1] = (item, reader.CurrentState, reader.BytesConsumed, state.Current.JsonPropertyName, state.Current.JsonPropertyNameAsString); reader.Skip(); state.Current.EndProperty(); } } } private bool ReadConstructorArgumentsWithContinuation(ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options) { while (true) { if (state.Current.PropertyState == StackFramePropertyState.None) { state.Current.PropertyState = StackFramePropertyState.ReadName; if (!reader.Read()) return false; } JsonParameterInfo jsonParameterInfo; JsonPropertyInfo jsonPropertyInfo; if ((int)state.Current.PropertyState < 2) { state.Current.PropertyState = StackFramePropertyState.Name; JsonTokenType tokenType = reader.TokenType; if (tokenType == JsonTokenType.EndObject) return true; if (TryLookupConstructorParameter(ref state, ref reader, options, out jsonParameterInfo)) jsonPropertyInfo = null; else { ReadOnlySpan<byte> propertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options); jsonPropertyInfo = JsonSerializer.LookupProperty(null, propertyName, ref state, out bool useExtensionProperty, false); state.Current.UseExtensionProperty = useExtensionProperty; } } else { jsonParameterInfo = state.Current.CtorArgumentState.JsonParameterInfo; jsonPropertyInfo = state.Current.JsonPropertyInfo; } if (jsonParameterInfo != null) { if (!HandleConstructorArgumentWithContinuation(ref state, ref reader, jsonParameterInfo)) return false; } else if (!HandlePropertyWithContinuation(ref state, ref reader, jsonPropertyInfo)) { break; } } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool HandleConstructorArgumentWithContinuation(ref ReadStack state, ref Utf8JsonReader reader, JsonParameterInfo jsonParameterInfo) { if ((int)state.Current.PropertyState < 3) { if (!jsonParameterInfo.ShouldDeserialize) { if (!reader.TrySkip()) return false; state.Current.EndConstructorParameter(); return true; } state.Current.PropertyState = StackFramePropertyState.ReadValue; if (!JsonConverter.SingleValueReadWithReadAhead(jsonParameterInfo.ConverterBase.ClassType, ref reader, ref state)) return false; } if (!ReadAndCacheConstructorArgument(ref state, ref reader, jsonParameterInfo)) return false; state.Current.EndConstructorParameter(); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool HandlePropertyWithContinuation(ref ReadStack state, ref Utf8JsonReader reader, JsonPropertyInfo jsonPropertyInfo) { if ((int)state.Current.PropertyState < 3) { if (!jsonPropertyInfo.ShouldDeserialize) { if (!reader.TrySkip()) return false; state.Current.EndProperty(); return true; } if (!ReadAheadPropertyValue(ref state, ref reader, jsonPropertyInfo)) return false; } object value; if (state.Current.UseExtensionProperty) { if (!jsonPropertyInfo.ReadJsonExtensionDataValue(ref state, ref reader, out value)) return false; } else if (!jsonPropertyInfo.ReadJsonAsObject(ref state, ref reader, out value)) { return false; } if (state.Current.CtorArgumentState.FoundPropertiesAsync == null) state.Current.CtorArgumentState.FoundPropertiesAsync = ArrayPool<(JsonPropertyInfo, object, string)>.Shared.Rent(Math.Max(1, state.Current.JsonClassInfo.PropertyCache.Count)); else if (state.Current.CtorArgumentState.FoundPropertyCount == state.Current.CtorArgumentState.FoundPropertiesAsync.Length) { (JsonPropertyInfo, object, string)[] array = ArrayPool<(JsonPropertyInfo, object, string)>.Shared.Rent(state.Current.CtorArgumentState.FoundPropertiesAsync.Length * 2); state.Current.CtorArgumentState.FoundPropertiesAsync.CopyTo(array, 0); ArrayPool<(JsonPropertyInfo, object, string)>.Shared.Return(state.Current.CtorArgumentState.FoundPropertiesAsync, true); state.Current.CtorArgumentState.FoundPropertiesAsync = array; } state.Current.CtorArgumentState.FoundPropertiesAsync[state.Current.CtorArgumentState.FoundPropertyCount++] = (jsonPropertyInfo, value, state.Current.JsonPropertyNameAsString); state.Current.EndProperty(); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void BeginRead(ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); if (state.Current.JsonClassInfo.ParameterCount != state.Current.JsonClassInfo.ParameterCache.Count) ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(base.ConstructorInfo, TypeToConvert); state.Current.JsonPropertyInfo = null; InitializeConstructorArgumentCaches(ref state, options); } protected virtual void EndRead(ref ReadStack state) { } protected virtual bool TryLookupConstructorParameter(ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options, out JsonParameterInfo jsonParameterInfo) { ReadOnlySpan<byte> propertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options); jsonParameterInfo = state.Current.JsonClassInfo.GetParameter(propertyName, ref state.Current, out byte[] utf8PropertyName); state.Current.CtorArgumentState.ParameterIndex++; state.Current.JsonPropertyName = utf8PropertyName; state.Current.CtorArgumentState.JsonParameterInfo = jsonParameterInfo; return jsonParameterInfo != null; } } }