< Summary

Information
Class: System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter<T>
Assembly: System.Text.Json
File(s): C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\Converters\Object\ObjectWithParameterizedConstructorConverter.cs
Line coverage
10%
Covered lines: 42
Uncovered lines: 358
Coverable lines: 400
Total lines: 652
Line coverage: 10.5%
Branch coverage
13%
Covered branches: 21
Total branches: 154
Branch coverage: 13.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
OnTryRead(...)22.09%868614.6%
ReadConstructorArguments(...)0%14140%
ReadConstructorArgumentsWithContinuation(...)5.55%181811.32%
HandleConstructorArgumentWithContinuation(...)0%10100%
HandlePropertyWithContinuation(...)0%18180%
BeginRead(...)50%2281.81%
TryLookupConstructorParameter(...)0%660%

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\Converters\Object\ObjectWithParameterizedConstructorConverter.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Buffers;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Runtime.CompilerServices;
 9using System.Text.Json.Serialization.Metadata;
 10
 11using FoundProperty = System.ValueTuple<System.Text.Json.Serialization.Metadata.JsonPropertyInfo, System.Text.Json.JsonR
 12using FoundPropertyAsync = System.ValueTuple<System.Text.Json.Serialization.Metadata.JsonPropertyInfo, object?, string?>
 13
 14namespace System.Text.Json.Serialization.Converters
 15{
 16    /// <summary>
 17    /// Implementation of <cref>JsonObjectConverter{T}</cref> that supports the deserialization
 18    /// of JSON objects using parameterized constructors.
 19    /// </summary>
 20    internal abstract partial class ObjectWithParameterizedConstructorConverter<T> : ObjectDefaultConverter<T> where T :
 21    {
 898822        internal sealed override bool ConstructorIsParameterized => true;
 23
 24        internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions opt
 23425        {
 23426            JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;
 27
 23428            if (!jsonTypeInfo.UsesParameterizedConstructor || state.Current.IsPopulating)
 029            {
 30                // Fall back to default object converter in following cases:
 31                // - if user configuration has invalidated the parameterized constructor
 32                // - we're continuing populating an object.
 033                return base.OnTryRead(ref reader, typeToConvert, options, ref state, out value);
 34            }
 35
 36            object obj;
 23437            ArgumentState argumentState = state.Current.CtorArgumentState!;
 38
 23439            if (!state.SupportContinuation && !state.Current.CanContainMetadata)
 040            {
 41                // Fast path that avoids maintaining state variables.
 42
 043                if (reader.TokenType != JsonTokenType.StartObject)
 044                {
 045                    ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type);
 46                }
 47
 048                if (state.ParentProperty?.TryGetPrePopulatedValue(ref state) == true)
 049                {
 050                    object populatedObject = state.Current.ReturnValue!;
 051                    PopulatePropertiesFastPath(populatedObject, jsonTypeInfo, options, ref reader, ref state);
 052                    value = (T)populatedObject;
 053                    return true;
 54                }
 55
 056                ReadOnlySpan<byte> originalSpan = reader.OriginalSpan;
 057                ReadOnlySequence<byte> originalSequence = reader.OriginalSequence;
 58
 059                ReadConstructorArguments(ref state, ref reader, options);
 60
 61                // We've read all ctor parameters and properties,
 62                // validate that all required parameters were provided
 63                // before calling the constructor which may throw.
 064                state.Current.ValidateAllRequiredPropertiesAreRead(jsonTypeInfo);
 65
 066                obj = (T)CreateObject(ref state.Current);
 67
 068                jsonTypeInfo.OnDeserializing?.Invoke(obj);
 69
 070                if (argumentState.FoundPropertyCount > 0)
 071                {
 72                    Utf8JsonReader tempReader;
 73
 074                    FoundProperty[]? properties = argumentState.FoundProperties;
 075                    Debug.Assert(properties != null);
 76
 077                    for (int i = 0; i < argumentState.FoundPropertyCount; i++)
 078                    {
 079                        JsonPropertyInfo jsonPropertyInfo = properties[i].Item1;
 080                        long resumptionByteIndex = properties[i].Item3;
 081                        byte[]? propertyNameArray = properties[i].Item4;
 082                        string? dataExtKey = properties[i].Item5;
 83
 084                        tempReader = originalSequence.IsEmpty
 085                            ? new Utf8JsonReader(
 086                                originalSpan.Slice(checked((int)resumptionByteIndex)),
 087                                isFinalBlock: true,
 088                                state: properties[i].Item2)
 089                            : new Utf8JsonReader(
 090                                originalSequence.Slice(resumptionByteIndex),
 091                                isFinalBlock: true,
 092                                state: properties[i].Item2);
 93
 094                        Debug.Assert(tempReader.TokenType == JsonTokenType.PropertyName);
 95
 096                        state.Current.JsonPropertyName = propertyNameArray;
 097                        state.Current.JsonPropertyInfo = jsonPropertyInfo;
 098                        state.Current.NumberHandling = jsonPropertyInfo.EffectiveNumberHandling;
 99
 0100                        bool useExtensionProperty = dataExtKey != null;
 101
 0102                        if (useExtensionProperty)
 0103                        {
 0104                            Debug.Assert(jsonPropertyInfo == state.Current.JsonTypeInfo.ExtensionDataProperty);
 0105                            state.Current.JsonPropertyNameAsString = dataExtKey;
 0106                            JsonSerializer.CreateExtensionDataProperty(obj, jsonPropertyInfo, options);
 0107                        }
 108
 0109                        ReadPropertyValue(obj, ref state, ref tempReader, jsonPropertyInfo, useExtensionProperty);
 0110                    }
 111
 0112                    FoundProperty[] toReturn = argumentState.FoundProperties!;
 0113                    argumentState.FoundProperties = null;
 0114                    ArrayPool<FoundProperty>.Shared.Return(toReturn, clearArray: true);
 0115                }
 0116            }
 117            else
 234118            {
 119                // Slower path that supports continuation and metadata reads.
 120
 234121                if (state.Current.ObjectState == StackFrameObjectState.None)
 234122                {
 234123                    if (reader.TokenType != JsonTokenType.StartObject)
 226124                    {
 226125                        ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type);
 126                    }
 127
 8128                    state.Current.ObjectState = StackFrameObjectState.StartToken;
 8129                }
 130
 131                // Read any metadata properties.
 8132                if (state.Current.CanContainMetadata && state.Current.ObjectState < StackFrameObjectState.ReadMetadata)
 0133                {
 0134                    if (!JsonSerializer.TryReadMetadata(this, jsonTypeInfo, ref reader, ref state))
 0135                    {
 0136                        value = default;
 0137                        return false;
 138                    }
 139
 0140                    if (state.Current.MetadataPropertyNames == MetadataPropertyName.Ref)
 0141                    {
 0142                        value = JsonSerializer.ResolveReferenceId<T>(ref state);
 0143                        return true;
 144                    }
 145
 0146                    state.Current.ObjectState = StackFrameObjectState.ReadMetadata;
 0147                }
 148
 149                // Dispatch to any polymorphic converters: should always be entered regardless of ObjectState progress
 8150                if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Type) != 0 &&
 8151                    state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStart
 8152                    ResolvePolymorphicConverter(jsonTypeInfo, ref state) is JsonConverter polymorphicConverter)
 0153                {
 0154                    Debug.Assert(!IsValueType);
 0155                    bool success = polymorphicConverter.OnTryReadAsObject(ref reader, polymorphicConverter.Type!, option
 0156                    value = (T)objectResult!;
 0157                    state.ExitPolymorphicConverter(success);
 0158                    return success;
 159                }
 160
 161                // We need to populate before we started reading constructor arguments.
 162                // Metadata is disallowed with Populate option and therefore ordering here is irrelevant.
 163                // Since state.Current.IsPopulating is being checked early on in this method the continuation
 164                // will be handled there.
 8165                if (state.ParentProperty?.TryGetPrePopulatedValue(ref state) == true)
 0166                {
 0167                    object populatedObject = state.Current.ReturnValue!;
 168
 0169                    jsonTypeInfo.OnDeserializing?.Invoke(populatedObject);
 0170                    state.Current.ObjectState = StackFrameObjectState.CreatedObject;
 0171                    state.Current.InitializePropertiesValidationState(jsonTypeInfo);
 0172                    return base.OnTryRead(ref reader, typeToConvert, options, ref state, out value);
 173                }
 174
 175                // Handle metadata post polymorphic dispatch
 8176                if (state.Current.ObjectState < StackFrameObjectState.ConstructorArguments)
 8177                {
 8178                    if (state.Current.CanContainMetadata)
 0179                    {
 0180                        JsonSerializer.ValidateMetadataForObjectConverter(ref state);
 0181                    }
 182
 8183                    if (state.Current.MetadataPropertyNames == MetadataPropertyName.Ref)
 0184                    {
 0185                        value = JsonSerializer.ResolveReferenceId<T>(ref state);
 0186                        return true;
 187                    }
 188
 8189                    BeginRead(ref state, options);
 190
 8191                    state.Current.ObjectState = StackFrameObjectState.ConstructorArguments;
 8192                }
 193
 8194                if (!ReadConstructorArgumentsWithContinuation(ref state, ref reader, options))
 0195                {
 0196                    value = default;
 0197                    return false;
 198                }
 199
 200                // We've read all ctor parameters and properties,
 201                // validate that all required parameters were provided
 202                // before calling the constructor which may throw.
 0203                state.Current.ValidateAllRequiredPropertiesAreRead(jsonTypeInfo);
 204
 0205                obj = (T)CreateObject(ref state.Current);
 206
 0207                if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Id) != 0)
 0208                {
 0209                    Debug.Assert(state.ReferenceId != null);
 0210                    Debug.Assert(options.ReferenceHandlingStrategy == JsonKnownReferenceHandler.Preserve);
 0211                    state.ReferenceResolver.AddReference(state.ReferenceId, obj);
 0212                    state.ReferenceId = null;
 0213                }
 214
 0215                jsonTypeInfo.OnDeserializing?.Invoke(obj);
 216
 0217                if (argumentState.FoundPropertyCount > 0)
 0218                {
 0219                    for (int i = 0; i < argumentState.FoundPropertyCount; i++)
 0220                    {
 0221                        JsonPropertyInfo jsonPropertyInfo = argumentState.FoundPropertiesAsync![i].Item1;
 0222                        object? propValue = argumentState.FoundPropertiesAsync![i].Item2;
 0223                        string? dataExtKey = argumentState.FoundPropertiesAsync![i].Item3;
 224
 0225                        if (dataExtKey == null)
 0226                        {
 0227                            Debug.Assert(jsonPropertyInfo.Set != null);
 228
 0229                            if (propValue is not null || !jsonPropertyInfo.IgnoreNullTokensOnRead || default(T) is not n
 0230                            {
 0231                                jsonPropertyInfo.Set(obj, propValue);
 0232                            }
 0233                        }
 234                        else
 0235                        {
 0236                            Debug.Assert(jsonPropertyInfo == state.Current.JsonTypeInfo.ExtensionDataProperty);
 237
 0238                            JsonSerializer.CreateExtensionDataProperty(obj, jsonPropertyInfo, options);
 0239                            object extDictionary = jsonPropertyInfo.GetValueAsObject(obj)!;
 240
 0241                            if (extDictionary is IDictionary<string, JsonElement> dict)
 0242                            {
 0243                                if (options.AllowDuplicateProperties)
 0244                                {
 0245                                    dict[dataExtKey] = (JsonElement)propValue!;
 0246                                }
 0247                                else if (!dict.TryAdd(dataExtKey, (JsonElement)propValue!))
 0248                                {
 0249                                    ThrowHelper.ThrowJsonException_DuplicatePropertyNotAllowed(dataExtKey);
 250                                }
 0251                            }
 252                            else
 0253                            {
 0254                                IDictionary<string, object> objDict = (IDictionary<string, object>)extDictionary;
 255
 0256                                if (options.AllowDuplicateProperties)
 0257                                {
 0258                                    objDict[dataExtKey] = propValue!;
 0259                                }
 0260                                else if (!objDict.TryAdd(dataExtKey, propValue!))
 0261                                {
 0262                                    ThrowHelper.ThrowJsonException_DuplicatePropertyNotAllowed(dataExtKey);
 263                                }
 0264                            }
 0265                        }
 0266                    }
 267
 0268                    FoundPropertyAsync[] toReturn = argumentState.FoundPropertiesAsync!;
 0269                    argumentState.FoundPropertiesAsync = null;
 0270                    ArrayPool<FoundPropertyAsync>.Shared.Return(toReturn, clearArray: true);
 0271                }
 0272            }
 273
 0274            jsonTypeInfo.OnDeserialized?.Invoke(obj);
 275
 276            // Unbox
 0277            Debug.Assert(obj != null);
 0278            value = (T)obj;
 279
 280            // Check if we are trying to update the UTF-8 property cache.
 0281            if (state.Current.PropertyRefCacheBuilder != null)
 0282            {
 0283                jsonTypeInfo.UpdateUtf8PropertyCache(ref state.Current);
 0284            }
 285
 0286            return true;
 0287        }
 288
 289        protected abstract void InitializeConstructorArgumentCaches(ref ReadStack state, JsonSerializerOptions options);
 290
 291        protected abstract bool ReadAndCacheConstructorArgument(scoped ref ReadStack state, ref Utf8JsonReader reader, J
 292
 293        protected abstract object CreateObject(ref ReadStackFrame frame);
 294
 295        /// <summary>
 296        /// Performs a full first pass of the JSON input and deserializes the ctor args.
 297        /// </summary>
 298        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 299        private void ReadConstructorArguments(scoped ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptio
 0300        {
 0301            BeginRead(ref state, options);
 302
 0303            while (true)
 0304            {
 305                // Read the next property name or EndObject.
 0306                reader.ReadWithVerify();
 307
 0308                JsonTokenType tokenType = reader.TokenType;
 309
 0310                if (tokenType == JsonTokenType.EndObject)
 0311                {
 0312                    return;
 313                }
 314
 315                // Read method would have thrown if otherwise.
 0316                Debug.Assert(tokenType == JsonTokenType.PropertyName);
 317
 0318                ReadOnlySpan<byte> unescapedPropertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options
 0319                if (isAlreadyReadMetadataProperty)
 0320                {
 0321                    Debug.Assert(options.AllowOutOfOrderMetadataProperties);
 0322                    reader.SkipWithVerify();
 0323                    state.Current.EndProperty();
 0324                    continue;
 325                }
 326
 0327                if (TryLookupConstructorParameter(
 0328                    unescapedPropertyName,
 0329                    ref state,
 0330                    options,
 0331                    out JsonPropertyInfo jsonPropertyInfo,
 0332                    out JsonParameterInfo? jsonParameterInfo))
 0333                {
 334                    // Set the property value.
 0335                    reader.ReadWithVerify();
 336
 0337                    if (!jsonParameterInfo.ShouldDeserialize)
 0338                    {
 339                        // The Utf8JsonReader.Skip() method will fail fast if it detects that we're reading
 340                        // from a partially read buffer, regardless of whether the next value is available.
 341                        // This can result in erroneous failures in cases where a custom converter is calling
 342                        // into a built-in converter (cf. https://github.com/dotnet/runtime/issues/74108).
 343                        // For this reason we need to call the TrySkip() method instead -- the serializer
 344                        // should guarantee sufficient read-ahead has been performed for the current object.
 0345                        bool success = reader.TrySkip();
 0346                        Debug.Assert(success, "Serializer should guarantee sufficient read-ahead has been done.");
 347
 0348                        state.Current.EndConstructorParameter();
 0349                        continue;
 350                    }
 351
 0352                    Debug.Assert(jsonParameterInfo.MatchingProperty != null);
 0353                    ReadAndCacheConstructorArgument(ref state, ref reader, jsonParameterInfo);
 354
 0355                    state.Current.EndConstructorParameter();
 0356                }
 357                else
 0358                {
 0359                    if (jsonPropertyInfo.CanDeserialize)
 0360                    {
 0361                        ArgumentState argumentState = state.Current.CtorArgumentState!;
 362
 0363                        if (argumentState.FoundProperties == null)
 0364                        {
 0365                            argumentState.FoundProperties =
 0366                                ArrayPool<FoundProperty>.Shared.Rent(Math.Max(1, state.Current.JsonTypeInfo.PropertyCach
 0367                        }
 0368                        else if (argumentState.FoundPropertyCount == argumentState.FoundProperties.Length)
 0369                        {
 370                            // Rare case where we can't fit all the JSON properties in the rented pool; we have to grow.
 371                            // This could happen if there are duplicate properties in the JSON.
 372
 0373                            var newCache = ArrayPool<FoundProperty>.Shared.Rent(argumentState.FoundProperties.Length * 2
 374
 0375                            argumentState.FoundProperties.CopyTo(newCache, 0);
 376
 0377                            FoundProperty[] toReturn = argumentState.FoundProperties;
 0378                            argumentState.FoundProperties = newCache!;
 379
 0380                            ArrayPool<FoundProperty>.Shared.Return(toReturn, clearArray: true);
 0381                        }
 382
 0383                        argumentState.FoundProperties[argumentState.FoundPropertyCount++] = (
 0384                            jsonPropertyInfo,
 0385                            reader.CurrentState,
 0386                            reader.BytesConsumed,
 0387                            state.Current.JsonPropertyName,
 0388                            state.Current.JsonPropertyNameAsString);
 0389                    }
 390
 0391                    reader.SkipWithVerify();
 0392                    state.Current.EndProperty();
 0393                }
 0394            }
 0395        }
 396
 397        private bool ReadConstructorArgumentsWithContinuation(scoped ref ReadStack state, ref Utf8JsonReader reader, Jso
 8398        {
 399            // Process all properties.
 8400            while (true)
 8401            {
 402                // Determine the property.
 8403                if (state.Current.PropertyState == StackFramePropertyState.None)
 8404                {
 8405                    if (!reader.Read())
 0406                    {
 0407                        return false;
 408                    }
 409
 0410                    state.Current.PropertyState = StackFramePropertyState.ReadName;
 0411                }
 412
 413                JsonParameterInfo? jsonParameterInfo;
 414                JsonPropertyInfo? jsonPropertyInfo;
 415
 0416                if (state.Current.PropertyState < StackFramePropertyState.Name)
 0417                {
 0418                    JsonTokenType tokenType = reader.TokenType;
 419
 0420                    if (tokenType == JsonTokenType.EndObject)
 0421                    {
 0422                        return true;
 423                    }
 424
 425                    // Read method would have thrown if otherwise.
 0426                    Debug.Assert(tokenType == JsonTokenType.PropertyName);
 427
 0428                    ReadOnlySpan<byte> unescapedPropertyName = JsonSerializer.GetPropertyName(ref state, ref reader, opt
 0429                    if (isAlreadyReadMetadataProperty)
 0430                    {
 0431                        Debug.Assert(options.AllowOutOfOrderMetadataProperties);
 0432                        reader.SkipWithVerify();
 0433                        state.Current.EndProperty();
 0434                        continue;
 435                    }
 436
 0437                    if (TryLookupConstructorParameter(
 0438                        unescapedPropertyName,
 0439                        ref state,
 0440                        options,
 0441                        out jsonPropertyInfo,
 0442                        out jsonParameterInfo))
 0443                    {
 0444                        jsonPropertyInfo = null;
 0445                    }
 446
 0447                    state.Current.PropertyState = StackFramePropertyState.Name;
 0448                }
 449                else
 0450                {
 0451                    jsonParameterInfo = state.Current.CtorArgumentState!.JsonParameterInfo;
 0452                    jsonPropertyInfo = state.Current.JsonPropertyInfo;
 0453                }
 454
 0455                if (jsonParameterInfo != null)
 0456                {
 0457                    Debug.Assert(jsonPropertyInfo == null);
 458
 0459                    if (!HandleConstructorArgumentWithContinuation(ref state, ref reader, jsonParameterInfo))
 0460                    {
 0461                        return false;
 462                    }
 0463                }
 464                else
 0465                {
 0466                    if (!HandlePropertyWithContinuation(ref state, ref reader, jsonPropertyInfo!))
 0467                    {
 0468                        return false;
 469                    }
 0470                }
 0471            }
 0472        }
 473
 474        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 475        private bool HandleConstructorArgumentWithContinuation(
 476            scoped ref ReadStack state,
 477            ref Utf8JsonReader reader,
 478            JsonParameterInfo jsonParameterInfo)
 0479        {
 0480            if (state.Current.PropertyState < StackFramePropertyState.ReadValue)
 0481            {
 0482                if (!jsonParameterInfo.ShouldDeserialize)
 0483                {
 0484                    if (!reader.TrySkipPartial(targetDepth: state.Current.OriginalDepth + 1))
 0485                    {
 0486                        return false;
 487                    }
 488
 0489                    state.Current.EndConstructorParameter();
 0490                    return true;
 491                }
 492
 0493                if (!reader.TryAdvanceWithOptionalReadAhead(jsonParameterInfo.EffectiveConverter.RequiresReadAhead))
 0494                {
 0495                    return false;
 496                }
 497
 0498                state.Current.PropertyState = StackFramePropertyState.ReadValue;
 0499            }
 500
 0501            if (!ReadAndCacheConstructorArgument(ref state, ref reader, jsonParameterInfo))
 0502            {
 0503                return false;
 504            }
 505
 0506            state.Current.EndConstructorParameter();
 0507            return true;
 0508        }
 509
 510        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 511        private static bool HandlePropertyWithContinuation(
 512            scoped ref ReadStack state,
 513            ref Utf8JsonReader reader,
 514            JsonPropertyInfo jsonPropertyInfo)
 0515        {
 0516            if (state.Current.PropertyState < StackFramePropertyState.ReadValue)
 0517            {
 0518                if (!jsonPropertyInfo.CanDeserialize)
 0519                {
 0520                    if (!reader.TrySkipPartial(targetDepth: state.Current.OriginalDepth + 1))
 0521                    {
 0522                        return false;
 523                    }
 524
 0525                    state.Current.EndProperty();
 0526                    return true;
 527                }
 528
 0529                if (!ReadAheadPropertyValue(ref state, ref reader, jsonPropertyInfo))
 0530                {
 0531                    return false;
 532                }
 533
 0534                state.Current.PropertyState = StackFramePropertyState.ReadValue;
 0535            }
 536
 537            object? propValue;
 538
 0539            if (state.Current.UseExtensionProperty)
 0540            {
 0541                if (!jsonPropertyInfo.ReadJsonExtensionDataValue(ref state, ref reader, out propValue))
 0542                {
 0543                    return false;
 544                }
 0545            }
 546            else
 0547            {
 0548                if (!jsonPropertyInfo.ReadJsonAsObject(ref state, ref reader, out propValue))
 0549                {
 0550                    return false;
 551                }
 0552            }
 553
 0554            Debug.Assert(jsonPropertyInfo.CanDeserialize);
 555
 556            // Ensure that the cache has enough capacity to add this property.
 557
 0558            ArgumentState argumentState = state.Current.CtorArgumentState!;
 559
 0560            if (argumentState.FoundPropertiesAsync == null)
 0561            {
 0562                argumentState.FoundPropertiesAsync = ArrayPool<FoundPropertyAsync>.Shared.Rent(Math.Max(1, state.Current
 0563            }
 0564            else if (argumentState.FoundPropertyCount == argumentState.FoundPropertiesAsync!.Length)
 0565            {
 566                // Rare case where we can't fit all the JSON properties in the rented pool; we have to grow.
 567                // This could happen if there are duplicate properties in the JSON.
 0568                var newCache = ArrayPool<FoundPropertyAsync>.Shared.Rent(argumentState.FoundPropertiesAsync!.Length * 2)
 569
 0570                argumentState.FoundPropertiesAsync!.CopyTo(newCache, 0);
 571
 0572                FoundPropertyAsync[] toReturn = argumentState.FoundPropertiesAsync!;
 0573                argumentState.FoundPropertiesAsync = newCache!;
 574
 0575                ArrayPool<FoundPropertyAsync>.Shared.Return(toReturn, clearArray: true);
 0576            }
 577
 578            // Cache the property name and value.
 0579            argumentState.FoundPropertiesAsync![argumentState.FoundPropertyCount++] = (
 0580                jsonPropertyInfo,
 0581                propValue,
 0582                state.Current.JsonPropertyNameAsString);
 583
 0584            state.Current.EndProperty();
 0585            return true;
 0586        }
 587
 588        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 589        private void BeginRead(scoped ref ReadStack state, JsonSerializerOptions options)
 8590        {
 8591            JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;
 592
 8593            jsonTypeInfo.ValidateCanBeUsedForPropertyMetadataSerialization();
 594
 8595            if (jsonTypeInfo.ParameterCount != jsonTypeInfo.ParameterCache.Length)
 0596            {
 0597                ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(Type);
 598            }
 599
 8600            state.Current.InitializePropertiesValidationState(jsonTypeInfo);
 601
 602            // Set current JsonPropertyInfo to null to avoid conflicts on push.
 8603            state.Current.JsonPropertyInfo = null;
 604
 8605            Debug.Assert(state.Current.CtorArgumentState != null);
 606
 8607            InitializeConstructorArgumentCaches(ref state, options);
 8608        }
 609
 610        /// <summary>
 611        /// Lookup the constructor parameter given its name in the reader.
 612        /// </summary>
 613        protected static bool TryLookupConstructorParameter(
 614            scoped ReadOnlySpan<byte> unescapedPropertyName,
 615            scoped ref ReadStack state,
 616            JsonSerializerOptions options,
 617            out JsonPropertyInfo jsonPropertyInfo,
 618            [NotNullWhen(true)] out JsonParameterInfo? jsonParameterInfo)
 0619        {
 0620            Debug.Assert(state.Current.JsonTypeInfo.Kind is JsonTypeInfoKind.Object);
 0621            Debug.Assert(state.Current.CtorArgumentState != null);
 622
 0623            jsonPropertyInfo = JsonSerializer.LookupProperty(
 0624                obj: null,
 0625                unescapedPropertyName,
 0626                ref state,
 0627                options,
 0628                out bool useExtensionProperty,
 0629                createExtensionProperty: false);
 630
 631            // Mark the property as read from the payload if it is mapped to a non-extension member.
 0632            if (!useExtensionProperty && jsonPropertyInfo != JsonPropertyInfo.s_missingProperty)
 0633            {
 0634                state.Current.MarkPropertyAsRead(jsonPropertyInfo);
 0635            }
 636
 0637            jsonParameterInfo = jsonPropertyInfo.AssociatedParameter;
 0638            if (jsonParameterInfo != null)
 0639            {
 0640                state.Current.JsonPropertyInfo = null;
 0641                state.Current.CtorArgumentState!.JsonParameterInfo = jsonParameterInfo;
 0642                state.Current.NumberHandling = jsonParameterInfo.NumberHandling;
 0643                return true;
 644            }
 645            else
 0646            {
 0647                state.Current.UseExtensionProperty = useExtensionProperty;
 0648                return false;
 649            }
 0650        }
 651    }
 652}