<PackageReference Include="System.Text.Json" Version="7.0.1" />

ObjectWithParameterizedConstructorConverter<T>

using System.Buffers; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization.Converters { internal abstract class ObjectWithParameterizedConstructorConverter<T> : ObjectDefaultConverter<T> { internal sealed override bool ConstructorIsParameterized => true; internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out T value) { JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo; if (jsonTypeInfo.CreateObject != null) return base.OnTryRead(ref reader, typeToConvert, options, ref state, out value); ArgumentState ctorArgumentState = state.Current.CtorArgumentState; object obj; if (!state.SupportContinuation && !state.Current.CanContainMetadata) { if (reader.TokenType != JsonTokenType.StartObject) ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); ReadOnlySpan<byte> originalSpan = reader.OriginalSpan; ReadOnlySequence<byte> originalSequence = reader.OriginalSequence; ReadConstructorArguments(ref state, ref reader, options); obj = (T)CreateObject(ref state.Current); jsonTypeInfo.OnDeserializing?.Invoke(obj); if (ctorArgumentState.FoundPropertyCount > 0) { (JsonPropertyInfo, JsonReaderState, long, byte[], string)[] foundProperties = ctorArgumentState.FoundProperties; for (int i = 0; i < ctorArgumentState.FoundPropertyCount; i++) { JsonPropertyInfo item = foundProperties[i].Item1; long item2 = foundProperties[i].Item3; byte[] item3 = foundProperties[i].Item4; string item4 = foundProperties[i].Item5; Utf8JsonReader reader2 = originalSequence.IsEmpty ? new Utf8JsonReader(originalSpan.Slice(checked((int)item2)), true, foundProperties[i].Item2) : new Utf8JsonReader(originalSequence.Slice(item2), true, foundProperties[i].Item2); state.Current.JsonPropertyName = item3; state.Current.JsonPropertyInfo = item; state.Current.NumberHandling = item.EffectiveNumberHandling; bool flag = item4 != null; if (flag) { state.Current.JsonPropertyNameAsString = item4; JsonSerializer.CreateExtensionDataProperty(obj, item, options); } ObjectDefaultConverter<T>.ReadPropertyValue(obj, ref state, ref reader2, item, flag); } (JsonPropertyInfo, JsonReaderState, long, byte[], string)[] foundProperties2 = ctorArgumentState.FoundProperties; ctorArgumentState.FoundProperties = null; ArrayPool<(JsonPropertyInfo, JsonReaderState, long, byte[], string)>.Shared.Return(foundProperties2, true); } } else { if (state.Current.ObjectState == StackFrameObjectState.None) { if (reader.TokenType != JsonTokenType.StartObject) ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); state.Current.ObjectState = StackFrameObjectState.StartToken; } if (state.Current.CanContainMetadata && (int)state.Current.ObjectState < 2) { if (!JsonSerializer.TryReadMetadata(this, jsonTypeInfo, ref reader, ref state)) { value = default(T); return false; } if (state.Current.MetadataPropertyNames == MetadataPropertyName.Ref) { value = JsonSerializer.ResolveReferenceId<T>(ref state); return true; } state.Current.ObjectState = StackFrameObjectState.ReadMetadata; } if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Type) && state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted) { JsonConverter jsonConverter = ResolvePolymorphicConverter(jsonTypeInfo, options, ref state); if (jsonConverter != null) { object value2; bool flag2 = jsonConverter.OnTryReadAsObject(ref reader, options, ref state, out value2); value = (T)value2; state.ExitPolymorphicConverter(flag2); return flag2; } } if ((int)state.Current.ObjectState < 3) { if (state.Current.CanContainMetadata) JsonSerializer.ValidateMetadataForObjectConverter(this, ref reader, ref state); if (state.Current.MetadataPropertyNames == MetadataPropertyName.Ref) { value = JsonSerializer.ResolveReferenceId<T>(ref state); return true; } BeginRead(ref state, ref reader, options); state.Current.ObjectState = StackFrameObjectState.ConstructorArguments; } if (!ReadConstructorArgumentsWithContinuation(ref state, ref reader, options)) { value = default(T); return false; } obj = (T)CreateObject(ref state.Current); if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Id)) { state.ReferenceResolver.AddReference(state.ReferenceId, obj); state.ReferenceId = null; } jsonTypeInfo.OnDeserializing?.Invoke(obj); if (ctorArgumentState.FoundPropertyCount > 0) { for (int j = 0; j < ctorArgumentState.FoundPropertyCount; j++) { JsonPropertyInfo item5 = ctorArgumentState.FoundPropertiesAsync[j].Item1; object item6 = ctorArgumentState.FoundPropertiesAsync[j].Item2; string item7 = ctorArgumentState.FoundPropertiesAsync[j].Item3; if (item7 == null) { if (item6 != null || !item5.IgnoreNullTokensOnRead || default(T) != null) { item5.Set(obj, item6); state.Current.MarkRequiredPropertyAsRead(item5); } } else { JsonSerializer.CreateExtensionDataProperty(obj, item5, options); 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; } } (JsonPropertyInfo, object, string)[] foundPropertiesAsync = ctorArgumentState.FoundPropertiesAsync; ctorArgumentState.FoundPropertiesAsync = null; ArrayPool<(JsonPropertyInfo, object, string)>.Shared.Return(foundPropertiesAsync, true); } } jsonTypeInfo.OnDeserialized?.Invoke(obj); state.Current.ValidateAllRequiredPropertiesAreRead(jsonTypeInfo); value = (T)obj; if (state.Current.PropertyRefCache != null) state.Current.JsonTypeInfo.UpdateSortedPropertyCache(ref state.Current); if (ctorArgumentState.ParameterRefCache != null) state.Current.JsonTypeInfo.UpdateSortedParameterCache(ref state.Current); return true; } protected abstract void InitializeConstructorArgumentCaches(ref ReadStack state, JsonSerializerOptions options); protected abstract bool ReadAndCacheConstructorArgument([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader, JsonParameterInfo jsonParameterInfo); protected abstract object CreateObject(ref ReadStackFrame frame); [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ReadConstructorArguments([System.Runtime.CompilerServices.ScopedRef] 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 jsonPropertyInfo = JsonSerializer.LookupProperty(null, propertyName, ref state, options, out useExtensionProperty, false); if (jsonPropertyInfo.CanDeserialize) { ArgumentState ctorArgumentState = state.Current.CtorArgumentState; if (ctorArgumentState.FoundProperties == null) ctorArgumentState.FoundProperties = ArrayPool<(JsonPropertyInfo, JsonReaderState, long, byte[], string)>.Shared.Rent(Math.Max(1, state.Current.JsonTypeInfo.PropertyCache.Count)); else if (ctorArgumentState.FoundPropertyCount == ctorArgumentState.FoundProperties.Length) { (JsonPropertyInfo, JsonReaderState, long, byte[], string)[] array = ArrayPool<(JsonPropertyInfo, JsonReaderState, long, byte[], string)>.Shared.Rent(ctorArgumentState.FoundProperties.Length * 2); ctorArgumentState.FoundProperties.CopyTo(array, 0); (JsonPropertyInfo, JsonReaderState, long, byte[], string)[] foundProperties = ctorArgumentState.FoundProperties; ctorArgumentState.FoundProperties = array; ArrayPool<(JsonPropertyInfo, JsonReaderState, long, byte[], string)>.Shared.Return(foundProperties, true); } ctorArgumentState.FoundProperties[ctorArgumentState.FoundPropertyCount++] = (jsonPropertyInfo, reader.CurrentState, reader.BytesConsumed, state.Current.JsonPropertyName, state.Current.JsonPropertyNameAsString); } reader.Skip(); state.Current.EndProperty(); } } } private bool ReadConstructorArgumentsWithContinuation([System.Runtime.CompilerServices.ScopedRef] 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, options, 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([System.Runtime.CompilerServices.ScopedRef] 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.RequiresReadAhead, ref reader, ref state)) return false; } if (!ReadAndCacheConstructorArgument(ref state, ref reader, jsonParameterInfo)) return false; state.Current.EndConstructorParameter(); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool HandlePropertyWithContinuation([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader, JsonPropertyInfo jsonPropertyInfo) { if ((int)state.Current.PropertyState < 3) { if (!jsonPropertyInfo.CanDeserialize) { if (!reader.TrySkip()) return false; state.Current.EndProperty(); return true; } if (!ObjectDefaultConverter<T>.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; } ArgumentState ctorArgumentState = state.Current.CtorArgumentState; if (ctorArgumentState.FoundPropertiesAsync == null) ctorArgumentState.FoundPropertiesAsync = ArrayPool<(JsonPropertyInfo, object, string)>.Shared.Rent(Math.Max(1, state.Current.JsonTypeInfo.PropertyCache.Count)); else if (ctorArgumentState.FoundPropertyCount == ctorArgumentState.FoundPropertiesAsync.Length) { (JsonPropertyInfo, object, string)[] array = ArrayPool<(JsonPropertyInfo, object, string)>.Shared.Rent(ctorArgumentState.FoundPropertiesAsync.Length * 2); ctorArgumentState.FoundPropertiesAsync.CopyTo(array, 0); (JsonPropertyInfo, object, string)[] foundPropertiesAsync = ctorArgumentState.FoundPropertiesAsync; ctorArgumentState.FoundPropertiesAsync = array; ArrayPool<(JsonPropertyInfo, object, string)>.Shared.Return(foundPropertiesAsync, true); } ctorArgumentState.FoundPropertiesAsync[ctorArgumentState.FoundPropertyCount++] = (jsonPropertyInfo, value, state.Current.JsonPropertyNameAsString); state.Current.EndProperty(); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void BeginRead([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options) { JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo; jsonTypeInfo.ValidateCanBeUsedForMetadataSerialization(); if (jsonTypeInfo.ParameterCount != jsonTypeInfo.ParameterCache.Count) ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(TypeToConvert); state.Current.InitializeRequiredPropertiesValidationState(jsonTypeInfo); state.Current.JsonPropertyInfo = null; InitializeConstructorArgumentCaches(ref state, options); } protected virtual bool TryLookupConstructorParameter([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options, out JsonParameterInfo jsonParameterInfo) { ReadOnlySpan<byte> propertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options); jsonParameterInfo = state.Current.JsonTypeInfo.GetParameter(propertyName, ref state.Current, out byte[] utf8PropertyName); state.Current.CtorArgumentState.ParameterIndex++; state.Current.JsonPropertyName = utf8PropertyName; state.Current.CtorArgumentState.JsonParameterInfo = jsonParameterInfo; state.Current.NumberHandling = jsonParameterInfo?.NumberHandling; return jsonParameterInfo != null; } } }