< Summary

Line coverage
55%
Covered lines: 272
Uncovered lines: 216
Coverable lines: 488
Total lines: 1088
Line coverage: 55.7%
Branch coverage
48%
Covered branches: 125
Total branches: 260
Branch coverage: 48%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.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.Collections.Generic;
 5using System.Diagnostics;
 6using System.Diagnostics.CodeAnalysis;
 7using System.Reflection;
 8using System.Threading;
 9
 10namespace System.Text.Json.Serialization.Metadata
 11{
 12    /// <summary>
 13    /// Provides JSON serialization-related metadata about a property or field defined in an object.
 14    /// </summary>
 15    [DebuggerDisplay("{DebuggerDisplay,nq}")]
 16    public abstract class JsonPropertyInfo
 17    {
 018        internal static readonly JsonPropertyInfo s_missingProperty = GetPropertyPlaceholder();
 19
 9496320        internal JsonTypeInfo? DeclaringTypeInfo { get; private set; }
 21
 22        /// <summary>
 23        /// Converter after applying CustomConverter (i.e. JsonConverterAttribute)
 24        /// </summary>
 25        internal JsonConverter EffectiveConverter
 26        {
 27            get
 4769228            {
 4769229                Debug.Assert(_effectiveConverter is not null);
 4769230                return _effectiveConverter;
 4769231            }
 32        }
 33
 34        private protected JsonConverter? _effectiveConverter;
 35
 36        /// <summary>
 37        /// Gets or sets a custom converter override for the current property.
 38        /// </summary>
 39        /// <exception cref="InvalidOperationException">
 40        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 41        /// </exception>
 42        /// <remarks>
 43        /// It is possible to use <see cref="JsonConverterFactory"/> instances with this property.
 44        ///
 45        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/>, the value of
 46        /// <see cref="CustomConverter"/> will be mapped from <see cref="JsonConverterAttribute" /> annotations.
 47        /// </remarks>
 48        public JsonConverter? CustomConverter
 49        {
 712350            get;
 51            set
 297652            {
 297653                VerifyMutable();
 297654                field = value;
 297655            }
 56        }
 57
 58        /// <summary>
 59        /// Gets or sets a getter delegate for the property.
 60        /// </summary>
 61        /// <exception cref="InvalidOperationException">
 62        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 63        /// </exception>
 64        /// <remarks>
 65        /// Setting to <see langword="null"/> will result in the property being skipped on serialization.
 66        /// </remarks>
 67        public Func<object, object?>? Get
 68        {
 297669            get => _untypedGet;
 70            set
 071            {
 072                VerifyMutable();
 073                SetGetter(value);
 074            }
 75        }
 76
 77        /// <summary>
 78        /// Gets or sets a setter delegate for the property.
 79        /// </summary>
 80        /// <exception cref="InvalidOperationException">
 81        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 82        /// </exception>
 83        /// <remarks>
 84        /// Setting to <see langword="null"/> will result in the property being skipped on deserialization.
 85        /// </remarks>
 86        public Action<object, object?>? Set
 87        {
 253188            get => _untypedSet;
 89            set
 090            {
 091                VerifyMutable();
 092                SetSetter(value);
 093                _isUserSpecifiedSetter = true;
 094            }
 95        }
 96
 97        private protected Func<object, object?>? _untypedGet;
 98        private protected Action<object, object?>? _untypedSet;
 99        private bool _isUserSpecifiedSetter;
 100
 101        private protected abstract void SetGetter(Delegate? getter);
 102        private protected abstract void SetSetter(Delegate? setter);
 103
 104        /// <summary>
 105        /// Gets or sets a predicate deciding whether the current property value should be serialized.
 106        /// </summary>
 107        /// <exception cref="InvalidOperationException">
 108        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 109        /// </exception>
 110        /// <remarks>
 111        /// The first parameter denotes the parent object, the second parameter denotes the property value.
 112        ///
 113        /// Setting the predicate to <see langword="null"/> is equivalent to always serializing the property value.
 114        ///
 115        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/>,
 116        /// the value of <see cref="JsonIgnoreAttribute.Condition"/> will map to this predicate.
 117        /// </remarks>
 118        public Func<object, object?, bool>? ShouldSerialize
 119        {
 0120            get => _shouldSerialize;
 121            set
 0122            {
 0123                VerifyMutable();
 0124                SetShouldSerialize(value);
 125                // Invalidate any JsonIgnore configuration if delegate set manually by user
 0126                _isUserSpecifiedShouldSerialize = true;
 0127                IgnoreDefaultValuesOnWrite = false;
 0128            }
 129        }
 130
 131        private protected Func<object, object?, bool>? _shouldSerialize;
 132        private bool _isUserSpecifiedShouldSerialize;
 133        private protected abstract void SetShouldSerialize(Delegate? predicate);
 134
 135        internal JsonIgnoreCondition? IgnoreCondition
 136        {
 0137            get => _ignoreCondition;
 138            set
 2976139            {
 2976140                Debug.Assert(!IsConfigured);
 2976141                ConfigureIgnoreCondition(value);
 2976142                _ignoreCondition = value;
 2976143            }
 144        }
 145
 146        private JsonIgnoreCondition? _ignoreCondition;
 147        private protected abstract void ConfigureIgnoreCondition(JsonIgnoreCondition? ignoreCondition);
 148
 149        /// <summary>
 150        /// Gets or sets a custom attribute provider for the current property.
 151        /// </summary>
 152        /// <exception cref="InvalidOperationException">
 153        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 154        /// </exception>
 155        /// <remarks>
 156        /// When resolving metadata via the built-in resolvers this
 157        /// will be populated with the underlying <see cref="MemberInfo" /> of the serialized property or field.
 158        ///
 159        /// Setting a custom attribute provider will have no impact on the contract model,
 160        /// but serves as metadata for downstream contract modifiers.
 161        /// </remarks>
 162        public ICustomAttributeProvider? AttributeProvider
 163        {
 164            get
 2976165            {
 2976166                Func<ICustomAttributeProvider>? attributeProviderFactory = Volatile.Read(ref AttributeProviderFactory);
 2976167                ICustomAttributeProvider? attributeProvider = _attributeProvider;
 168
 2976169                if (attributeProvider is null && attributeProviderFactory is not null)
 0170                {
 0171                    _attributeProvider = attributeProvider = attributeProviderFactory();
 0172                    Volatile.Write(ref AttributeProviderFactory, null);
 0173                }
 174
 2976175                return attributeProvider;
 2976176            }
 177            set
 2976178            {
 2976179                VerifyMutable();
 180
 2976181                _attributeProvider = value;
 2976182                Volatile.Write(ref AttributeProviderFactory, null);
 2976183            }
 184        }
 185
 186        // Metadata emanating from the source generator use delayed attribute provider initialization
 187        // ensuring that reflection metadata resolution remains pay-for-play and is trimmable.
 188        internal Func<ICustomAttributeProvider>? AttributeProviderFactory;
 189        private ICustomAttributeProvider? _attributeProvider;
 190
 191        /// <summary>
 192        /// Gets or sets a value indicating if the property or field should be replaced or populated during deserializat
 193        /// </summary>
 194        /// <remarks>
 195        /// Initial value for this property is based on the presence of <see cref="JsonObjectCreationHandlingAttribute"/
 196        /// When <see langword="null"/> effective handling will be resolved based on
 197        /// capability of property converter to populate, containing type's <see cref="JsonTypeInfo.PreferredPropertyObj
 198        /// and <see cref="JsonSerializerOptions.PreferredObjectCreationHandling"/> value.
 199        /// </remarks>
 200        public JsonObjectCreationHandling? ObjectCreationHandling
 201        {
 7123202            get;
 203            set
 2976204            {
 2976205                VerifyMutable();
 206
 2976207                if (value is not null)
 0208                {
 0209                    if (!JsonSerializer.IsValidCreationHandlingValue(value.Value))
 0210                    {
 0211                        throw new ArgumentOutOfRangeException(nameof(value));
 212                    }
 0213                }
 214
 2976215                field = value;
 2976216            }
 217        }
 218
 11270219        internal JsonObjectCreationHandling EffectiveObjectCreationHandling { get; private set; }
 220
 12924221        internal string? MemberName { get; set; } // Do not rename (legacy schema generation)
 18116222        internal MemberTypes MemberType { get; set; }
 2976223        internal bool IsVirtual { get; set; }
 224
 225        /// <summary>
 226        /// Gets or sets a value indicating whether the return type of the getter is annotated as nullable.
 227        /// </summary>
 228        /// <exception cref="InvalidOperationException">
 229        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 230        ///
 231        /// -or-
 232        ///
 233        /// The current <see cref="PropertyType"/> is not a reference type or <see cref="Nullable{T}"/>.
 234        /// </exception>
 235        /// <remarks>
 236        /// Contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext"/>,
 237        /// derive the value of this property from nullable reference type annotations, including annotations
 238        /// from attributes such as <see cref="NotNullAttribute"/> or <see cref="MaybeNullAttribute"/>.
 239        ///
 240        /// This property has no effect on serialization unless the <see cref="JsonSerializerOptions.RespectNullableAnno
 241        /// property has been enabled, in which case the serializer will reject any <see langword="null"/> values return
 242        /// </remarks>
 243        public bool IsGetNullable
 244        {
 0245            get => _isGetNullable;
 246            set
 894247            {
 894248                VerifyMutable();
 249
 894250                if (value && !PropertyTypeCanBeNull)
 0251                {
 0252                    ThrowHelper.ThrowInvalidOperationException_PropertyTypeNotNullable(this);
 253                }
 254
 894255                _isGetNullable = value;
 894256            }
 257        }
 258
 259        private bool _isGetNullable;
 260
 261        /// <summary>
 262        /// Gets or sets a value indicating whether the input type of the setter is annotated as nullable.
 263        /// </summary>
 264        /// <exception cref="InvalidOperationException">
 265        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 266        ///
 267        /// -or-
 268        ///
 269        /// The current <see cref="PropertyType"/> is not a reference type or <see cref="Nullable{T}"/>.
 270        /// </exception>
 271        /// <remarks>
 272        /// Contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext"/>,
 273        /// derive the value of this property from nullable reference type annotations, including annotations
 274        /// from attributes such as <see cref="AllowNullAttribute"/> or <see cref="DisallowNullAttribute"/>.
 275        ///
 276        /// This property has no effect on deserialization unless the <see cref="JsonSerializerOptions.RespectNullableAn
 277        /// property has been enabled, in which case the serializer will reject any <see langword="null"/> deserializati
 278        ///
 279        /// If the property has been associated with a deserialization constructor parameter,
 280        /// this setting reflected the nullability annotation of the parameter and not the property setter.
 281        /// </remarks>
 282        public bool IsSetNullable
 283        {
 0284            get => _isSetNullable;
 285            set
 894286            {
 894287                VerifyMutable();
 288
 894289                if (value && !PropertyTypeCanBeNull)
 0290                {
 0291                    ThrowHelper.ThrowInvalidOperationException_PropertyTypeNotNullable(this);
 292                }
 293
 894294                _isSetNullable = value;
 894295            }
 296        }
 297
 298        private protected bool _isSetNullable;
 299
 300        /// <summary>
 301        /// Specifies whether the current property is a special extension data property.
 302        /// </summary>
 303        /// <exception cref="InvalidOperationException">
 304        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 305        ///
 306        /// -or-
 307        ///
 308        /// The current <see cref="PropertyType"/> is not valid for use with extension data.
 309        /// </exception>
 310        /// <remarks>
 311        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 312        /// the value of this property will be mapped from <see cref="JsonExtensionDataAttribute"/> annotations.
 313        /// </remarks>
 314        public bool IsExtensionData
 315        {
 2976316            get;
 317            set
 2976318            {
 2976319                VerifyMutable();
 320
 2976321                if (value && !JsonTypeInfo.IsValidExtensionDataProperty(PropertyType))
 0322                {
 0323                    ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(this);
 324                }
 325
 2976326                field = value;
 2976327            }
 328        }
 329
 330        /// <summary>
 331        /// Specifies whether the current property is required for deserialization to be successful.
 332        /// </summary>
 333        /// <exception cref="InvalidOperationException">
 334        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 335        /// </exception>
 336        /// <remarks>
 337        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 338        /// the value of this property will be mapped from <see cref="JsonRequiredAttribute"/> annotations.
 339        ///
 340        /// For contracts using <see cref="DefaultJsonTypeInfoResolver"/>, properties using the <see langword="required"
 341        /// will also map to this setting, unless deserialization uses a SetsRequiredMembersAttribute on a constructor t
 342        /// <see langword="required"/> keyword is currently not supported in <see cref="JsonSerializerContext"/> contrac
 343        /// </remarks>
 344        public bool IsRequired
 345        {
 10099346            get => _isRequired;
 347            set
 2976348            {
 2976349                VerifyMutable();
 2976350                _isRequired = value;
 2976351            }
 352        }
 353
 354        private protected bool _isRequired;
 355
 356        /// <summary>
 357        /// Gets the constructor parameter associated with the current property.
 358        /// </summary>
 359        /// <remarks>
 360        /// Returns the <see cref="JsonParameterInfo"/> metadata for the parameter in the
 361        /// deserialization constructor that has been associated with the current property.
 362        ///
 363        /// A constructor parameter is matched to a property or field if they are of the
 364        /// same type and have the same name, up to case insensitivity. Each constructor
 365        /// parameter must be matched to exactly one property of field.
 366        /// </remarks>
 5994367        public JsonParameterInfo? AssociatedParameter { get; internal set; }
 368
 7123369        internal JsonPropertyInfo(Type declaringType, Type propertyType, JsonTypeInfo? declaringTypeInfo, JsonSerializer
 7123370        {
 7123371            Debug.Assert(declaringTypeInfo is null || declaringType.IsAssignableFrom(declaringTypeInfo.Type));
 372
 7123373            DeclaringType = declaringType;
 7123374            PropertyType = propertyType;
 7123375            DeclaringTypeInfo = declaringTypeInfo; // null declaringTypeInfo means it's not tied yet
 7123376            Options = options;
 377
 7123378            _isGetNullable = _isSetNullable = PropertyTypeCanBeNull;
 7123379        }
 380
 381        internal static JsonPropertyInfo GetPropertyPlaceholder()
 0382        {
 0383            JsonPropertyInfo info = new JsonPropertyInfo<object>(typeof(object), declaringTypeInfo: null, options: null!
 384
 0385            Debug.Assert(!info.IsForTypeInfo);
 0386            Debug.Assert(!info.CanSerialize);
 0387            Debug.Assert(!info.CanDeserialize);
 388
 0389            info.Name = string.Empty;
 390
 0391            return info;
 0392        }
 393
 394        /// <summary>
 395        /// Gets the declaring type of the property.
 396        /// </summary>
 0397        public Type DeclaringType { get; }
 398
 399        /// <summary>
 400        /// Gets the type of the current property.
 401        /// </summary>
 23774402        public Type PropertyType { get; }
 403
 404        private protected void VerifyMutable()
 25596405        {
 25596406            DeclaringTypeInfo?.VerifyMutable();
 25596407        }
 408
 47368409        internal bool IsConfigured { get; private set; }
 410
 411        internal void Configure()
 7123412        {
 7123413            Debug.Assert(DeclaringTypeInfo is not null);
 7123414            Debug.Assert(!IsConfigured);
 415
 7123416            if (IsIgnored)
 0417            {
 418                // Avoid configuring JsonIgnore.Always properties
 419                // to avoid failing on potentially unsupported types.
 0420                CanSerialize = false;
 0421                CanDeserialize = false;
 0422            }
 423            else
 7123424            {
 7123425                _jsonTypeInfo ??= Options.GetTypeInfoInternal(PropertyType);
 7123426                _jsonTypeInfo.EnsureConfigured();
 427
 7123428                DetermineEffectiveConverter(_jsonTypeInfo);
 7123429                DetermineNumberHandlingForProperty();
 7123430                DetermineEffectiveObjectCreationHandlingForProperty();
 7123431                DetermineSerializationCapabilities();
 7123432                DetermineIgnoreCondition();
 7123433            }
 434
 7123435            if (IsForTypeInfo)
 4147436            {
 4147437                DetermineNumberHandlingForTypeInfo();
 4147438            }
 439            else
 2976440            {
 2976441                ValidateAndCachePropertyName();
 2976442            }
 443
 7123444            if (IsRequired)
 0445            {
 0446                if (!CanDeserialize &&
 0447                    !(AssociatedParameter?.IsRequiredParameter is true &&
 0448                      Options.RespectRequiredConstructorParameters))
 0449                {
 0450                    ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndNotDeserializable(this);
 451                }
 452
 0453                if (IsExtensionData)
 0454                {
 0455                    ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndExtensionData(this);
 456                }
 457
 0458                Debug.Assert(!IgnoreNullTokensOnRead);
 0459            }
 460
 7123461            IsConfigured = true;
 7123462        }
 463
 464        private protected abstract void DetermineEffectiveConverter(JsonTypeInfo jsonTypeInfo);
 465
 466        [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 467        [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 468        internal abstract void DetermineReflectionPropertyAccessors(MemberInfo memberInfo, bool useNonPublicAccessors);
 469
 470        private void ValidateAndCachePropertyName()
 2976471        {
 2976472            Debug.Assert(Name is not null);
 473
 2976474            if (Options.ReferenceHandlingStrategy is JsonKnownReferenceHandler.Preserve &&
 2976475                this is { DeclaringType.IsValueType: false, IsIgnored: false, IsExtensionData: false } &&
 2976476                Name is JsonSerializer.IdPropertyName or JsonSerializer.RefPropertyName)
 0477            {
 478                // Validate potential conflicts with reference preservation metadata property names.
 479                // Conflicts with polymorphic type discriminators are contextual and need to be
 480                // handled separately by the PolymorphicTypeResolver type.
 481
 0482                ThrowHelper.ThrowInvalidOperationException_PropertyConflictsWithMetadataPropertyName(DeclaringType, Name
 483            }
 484
 2976485            NameAsUtf8Bytes = Encoding.UTF8.GetBytes(Name);
 2976486            EscapedNameSection = JsonHelpers.GetEscapedPropertyNameSection(NameAsUtf8Bytes, Options.Encoder);
 2976487        }
 488
 489        private void DetermineIgnoreCondition()
 7123490        {
 7123491            if (_ignoreCondition is not null)
 0492            {
 493                // Do not apply global policy if already configured on the property level.
 0494                return;
 495            }
 496
 497#pragma warning disable SYSLIB0020 // JsonSerializerOptions.IgnoreNullValues is obsolete
 7123498            if (Options.IgnoreNullValues)
 499#pragma warning restore SYSLIB0020
 0500            {
 0501                Debug.Assert(Options.DefaultIgnoreCondition == JsonIgnoreCondition.Never);
 0502                if (PropertyTypeCanBeNull)
 0503                {
 0504                    IgnoreNullTokensOnRead = !_isUserSpecifiedSetter && !IsRequired;
 0505                    IgnoreDefaultValuesOnWrite = ShouldSerialize is null;
 0506                }
 0507            }
 7123508            else if (Options.DefaultIgnoreCondition == JsonIgnoreCondition.WhenWritingNull)
 0509            {
 0510                if (PropertyTypeCanBeNull)
 0511                {
 0512                    IgnoreDefaultValuesOnWrite = ShouldSerialize is null;
 0513                }
 0514            }
 7123515            else if (Options.DefaultIgnoreCondition == JsonIgnoreCondition.WhenWritingDefault)
 0516            {
 0517                IgnoreDefaultValuesOnWrite = ShouldSerialize is null;
 0518            }
 7123519        }
 520
 521        private void DetermineSerializationCapabilities()
 7123522        {
 7123523            Debug.Assert(EffectiveConverter is not null, "Must have calculated the effective converter.");
 7123524            CanSerialize = HasGetter;
 7123525            CanDeserialize = HasSetter;
 526
 7123527            Debug.Assert(MemberType is 0 or MemberTypes.Field or MemberTypes.Property);
 7123528            if (MemberType == 0 || _ignoreCondition is not null)
 4147529            {
 530                // No policy to be applied if either:
 531                // 1. JsonPropertyInfo is a custom instance (not generated via reflection or sourcegen).
 532                // 2. A JsonIgnoreCondition has been specified on the property level.
 4147533                CanDeserializeOrPopulate = CanDeserialize || EffectiveObjectCreationHandling == JsonObjectCreationHandli
 4147534                return;
 535            }
 536
 2976537            if ((EffectiveConverter.ConverterStrategy & (ConverterStrategy.Enumerable | ConverterStrategy.Dictionary)) !
 445538            {
 539                // Properties of collections types that only have setters are not supported.
 445540                if (Get is null && Set is not null && !_isUserSpecifiedSetter)
 0541                {
 0542                    CanDeserialize = false;
 0543                }
 445544            }
 545            else
 2531546            {
 547                // For read-only properties of non-collection types, apply IgnoreReadOnlyProperties/Fields policy,
 548                // unless a `ShouldSerialize` predicate has been explicitly applied by the user (null or non-null).
 2531549                if (Get is not null && Set is null && IgnoreReadOnlyMember && !_isUserSpecifiedShouldSerialize)
 0550                {
 0551                    CanSerialize = false;
 0552                }
 2531553            }
 554
 2976555            CanDeserializeOrPopulate = CanDeserialize || EffectiveObjectCreationHandling == JsonObjectCreationHandling.P
 7123556        }
 557
 558        private void DetermineNumberHandlingForTypeInfo()
 4147559        {
 4147560            Debug.Assert(DeclaringTypeInfo is not null, "We should have ensured parent is assigned in JsonTypeInfo");
 4147561            Debug.Assert(!DeclaringTypeInfo.IsConfigured);
 562
 4147563            JsonNumberHandling? declaringTypeNumberHandling = DeclaringTypeInfo.NumberHandling;
 564
 4147565            if (declaringTypeNumberHandling is not null && declaringTypeNumberHandling != JsonNumberHandling.Strict && !
 0566            {
 0567                ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this);
 568            }
 569
 4147570            if (NumberHandingIsApplicable())
 1530571            {
 572                // This logic is to honor JsonNumberHandlingAttribute placed on
 573                // custom collections e.g. public class MyNumberList : List<int>.
 574
 575                // Priority 1: Get handling from the type (parent type in this case is the type itself).
 1530576                EffectiveNumberHandling = declaringTypeNumberHandling;
 577
 578                // Priority 2: Get handling from JsonSerializerOptions instance.
 1530579                if (!EffectiveNumberHandling.HasValue && Options.NumberHandling != JsonNumberHandling.Strict)
 964580                {
 964581                    EffectiveNumberHandling = Options.NumberHandling;
 964582                }
 1530583            }
 4147584        }
 585
 586        private void DetermineNumberHandlingForProperty()
 7123587        {
 7123588            Debug.Assert(DeclaringTypeInfo is not null, "We should have ensured parent is assigned in JsonTypeInfo");
 7123589            Debug.Assert(!IsConfigured, "Should not be called post-configuration.");
 7123590            Debug.Assert(_jsonTypeInfo is not null, "Must have already been determined on configuration.");
 591
 7123592            bool numberHandlingIsApplicable = NumberHandingIsApplicable();
 593
 7123594            if (numberHandlingIsApplicable)
 2284595            {
 596                // Priority 1: Get handling from attribute on property/field, its parent class type or property type.
 2284597                JsonNumberHandling? handling = NumberHandling ?? DeclaringTypeInfo.NumberHandling ?? _jsonTypeInfo.Numbe
 598
 599                // Priority 2: Get handling from JsonSerializerOptions instance.
 2284600                if (!handling.HasValue && Options.NumberHandling != JsonNumberHandling.Strict)
 1257601                {
 1257602                    handling = Options.NumberHandling;
 1257603                }
 604
 2284605                EffectiveNumberHandling = handling;
 2284606            }
 4839607            else if (NumberHandling.HasValue && NumberHandling != JsonNumberHandling.Strict)
 0608            {
 0609                ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this);
 610            }
 7123611        }
 612
 613        private void DetermineEffectiveObjectCreationHandlingForProperty()
 7123614        {
 7123615            Debug.Assert(EffectiveConverter is not null, "Must have calculated the effective converter.");
 7123616            Debug.Assert(DeclaringTypeInfo is not null, "We should have ensured parent is assigned in JsonTypeInfo");
 7123617            Debug.Assert(!IsConfigured, "Should not be called post-configuration.");
 618
 7123619            JsonObjectCreationHandling effectiveObjectCreationHandling = JsonObjectCreationHandling.Replace;
 7123620            if (ObjectCreationHandling is null)
 7123621            {
 622                // Consult type-level configuration, then global configuration.
 623                // Ignore global configuration if we're using a parameterized constructor.
 7123624                JsonObjectCreationHandling preferredCreationHandling =
 7123625                    DeclaringTypeInfo.PreferredPropertyObjectCreationHandling
 7123626                    ?? (DeclaringTypeInfo.DetermineUsesParameterizedConstructor()
 7123627                        ? JsonObjectCreationHandling.Replace
 7123628                        : Options.PreferredObjectCreationHandling);
 629
 7123630                bool canPopulate =
 7123631                    preferredCreationHandling == JsonObjectCreationHandling.Populate &&
 7123632                    EffectiveConverter.CanPopulate &&
 7123633                    Get is not null &&
 7123634                    (!PropertyType.IsValueType || Set is not null) &&
 7123635                    !DeclaringTypeInfo.SupportsPolymorphicDeserialization &&
 7123636                    !(Set is null && IgnoreReadOnlyMember);
 637
 7123638                effectiveObjectCreationHandling = canPopulate ? JsonObjectCreationHandling.Populate : JsonObjectCreation
 7123639            }
 0640            else if (ObjectCreationHandling == JsonObjectCreationHandling.Populate)
 0641            {
 0642                if (!EffectiveConverter.CanPopulate)
 0643                {
 0644                    ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPopulateNotSupportedByConverter(thi
 645                }
 646
 0647                if (Get is null)
 0648                {
 0649                    ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyMustHaveAGetter(this);
 650                }
 651
 0652                if (PropertyType.IsValueType && Set is null)
 0653                {
 0654                    ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyValueTypeMustHaveASetter(th
 655                }
 656
 0657                Debug.Assert(_jsonTypeInfo is not null);
 0658                Debug.Assert(_jsonTypeInfo.IsConfigurationStarted);
 0659                if (JsonTypeInfo.SupportsPolymorphicDeserialization)
 0660                {
 0661                    ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyCannotAllowPolymorphicDeser
 662                }
 663
 0664                if (Set is null && IgnoreReadOnlyMember)
 0665                {
 0666                    ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyCannotAllowReadOnlyMember(t
 667                }
 668
 0669                effectiveObjectCreationHandling = JsonObjectCreationHandling.Populate;
 0670            }
 671
 7123672            if (effectiveObjectCreationHandling is JsonObjectCreationHandling.Populate)
 0673            {
 0674                if (DeclaringTypeInfo.DetermineUsesParameterizedConstructor())
 0675                {
 0676                    ThrowHelper.ThrowNotSupportedException_ObjectCreationHandlingPropertyDoesNotSupportParameterizedCons
 677                }
 678
 0679                if (Options.ReferenceHandlingStrategy != JsonKnownReferenceHandler.Unspecified)
 0680                {
 0681                    ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyCannotAllowReferenceHandlin
 682                }
 0683            }
 684
 685            // Validation complete, commit configuration.
 7123686            EffectiveObjectCreationHandling = effectiveObjectCreationHandling;
 7123687        }
 688
 689        private bool NumberHandingIsApplicable()
 11270690        {
 11270691            if (EffectiveConverter.IsInternalConverterForNumberType)
 3053692            {
 3053693                return true;
 694            }
 695
 696            Type potentialNumberType;
 8217697            if (!EffectiveConverter.IsInternalConverter ||
 8217698                ((ConverterStrategy.Enumerable | ConverterStrategy.Dictionary) & EffectiveConverter.ConverterStrategy) =
 6834699            {
 6834700                potentialNumberType = PropertyType;
 6834701            }
 702            else
 1383703            {
 1383704                Debug.Assert(EffectiveConverter.ElementType != null);
 1383705                potentialNumberType = EffectiveConverter.ElementType;
 1383706            }
 707
 8217708            potentialNumberType = Nullable.GetUnderlyingType(potentialNumberType) ?? potentialNumberType;
 709
 8217710            return potentialNumberType == typeof(byte) ||
 8217711                potentialNumberType == typeof(decimal) ||
 8217712                potentialNumberType == typeof(double) ||
 8217713                potentialNumberType == typeof(short) ||
 8217714                potentialNumberType == typeof(int) ||
 8217715                potentialNumberType == typeof(long) ||
 8217716                potentialNumberType == typeof(sbyte) ||
 8217717                potentialNumberType == typeof(float) ||
 8217718                potentialNumberType == typeof(ushort) ||
 8217719                potentialNumberType == typeof(uint) ||
 8217720                potentialNumberType == typeof(ulong) ||
 8217721#if NET
 8217722                potentialNumberType == typeof(Half) ||
 8217723#endif
 8217724#if NET
 8217725                potentialNumberType == typeof(Int128) ||
 8217726                potentialNumberType == typeof(UInt128) ||
 8217727#endif
 8217728#if NET11_0_OR_GREATER
 8217729                potentialNumberType == typeof(System.Numerics.BFloat16) ||
 8217730                potentialNumberType == typeof(System.Numerics.Decimal32) ||
 8217731                potentialNumberType == typeof(System.Numerics.Decimal64) ||
 8217732                potentialNumberType == typeof(System.Numerics.Decimal128) ||
 8217733#endif
 8217734                potentialNumberType == typeof(object);
 11270735        }
 736
 737        /// <summary>
 738        /// Creates a <see cref="JsonPropertyInfo"/> instance whose type matches that of the current property.
 739        /// </summary>
 740        internal abstract void AddJsonParameterInfo(JsonParameterInfoValues parameterInfoValues);
 741
 742        internal abstract bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer);
 743        internal abstract bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter write
 744
 745        internal abstract object? GetValueAsObject(object obj);
 746
 7123747        internal bool HasGetter => _untypedGet is not null;
 7123748        internal bool HasSetter => _untypedSet is not null;
 0749        internal bool IgnoreNullTokensOnRead { get; private protected set; }
 0750        internal bool IgnoreDefaultValuesOnWrite { get; private protected set; }
 751
 752        internal bool IgnoreReadOnlyMember
 753        {
 754            get
 0755            {
 0756                Debug.Assert(MemberType == MemberTypes.Property || MemberType == MemberTypes.Field || MemberType == defa
 0757                return MemberType switch
 0758                {
 0759                    MemberTypes.Property => Options.IgnoreReadOnlyProperties,
 0760                    MemberTypes.Field => Options.IgnoreReadOnlyFields,
 0761                    _ => false,
 0762                };
 0763            }
 764        }
 765
 766        /// <summary>
 767        /// True if the corresponding cref="JsonTypeInfo.PropertyInfoForTypeInfo"/> is this instance.
 768        /// </summary>
 11270769        internal bool IsForTypeInfo { get; init; }
 770
 771        // There are 3 copies of the property name:
 772        // 1) Name. The unescaped property name.
 773        // 2) NameAsUtf8Bytes. The Utf8 version of Name. Used during deserialization for property lookup.
 774        // 3) EscapedNameSection. The escaped version of NameAsUtf8Bytes plus the wrapping quotes and a trailing colon. 
 775
 776        /// <summary>
 777        /// Gets or sets the JSON property name used when serializing the property.
 778        /// </summary>
 779        /// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
 780        /// <exception cref="InvalidOperationException">
 781        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 782        /// </exception>
 783        /// <remarks>
 784        /// The value of <see cref="Name"/> cannot conflict with that of other <see cref="JsonPropertyInfo"/> defined in
 785        ///
 786        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 787        /// the value typically reflects the underlying .NET member name, the name derived from <see cref="JsonSerialize
 788        /// or the value specified in <see cref="JsonPropertyNameAttribute" />.
 789        /// </remarks>
 790        public string Name
 791        {
 792            get
 14880793            {
 14880794                Debug.Assert(_name is not null);
 14880795                return _name;
 14880796            }
 797            set
 2976798            {
 2976799                VerifyMutable();
 800
 2976801                ArgumentNullException.ThrowIfNull(value);
 802
 2976803                _name = value;
 2976804            }
 805        }
 806
 807        private string? _name;
 808
 809        /// <summary>
 810        /// Utf8 version of Name.
 811        /// </summary>
 36319812        internal byte[] NameAsUtf8Bytes { get; private set; } = null!;
 813
 814        /// <summary>
 815        /// The escaped name passed to the writer.
 816        /// </summary>
 10099817        internal byte[] EscapedNameSection { get; private set; } = null!;
 818
 819        /// <summary>
 820        /// Gets the <see cref="JsonSerializerOptions"/> value associated with the current contract instance.
 821        /// </summary>
 50754822        public JsonSerializerOptions Options { get; }
 823
 824        /// <summary>
 825        /// Gets or sets the serialization order for the current property.
 826        /// </summary>
 827        /// <exception cref="InvalidOperationException">
 828        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 829        /// </exception>
 830        /// <remarks>
 831        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 832        /// the value of this property will be mapped from <see cref="JsonPropertyOrderAttribute"/> annotations.
 833        /// </remarks>
 834        public int Order
 835        {
 8928836            get;
 837            set
 2976838            {
 2976839                VerifyMutable();
 2976840                field = value;
 2976841            }
 842        }
 843
 844        internal bool ReadJsonAndAddExtensionProperty(
 845            object obj,
 846            scoped ref ReadStack state,
 847            ref Utf8JsonReader reader)
 0848        {
 0849            object propValue = GetValueAsObject(obj)!;
 850
 0851            if (propValue is IDictionary<string, object?> dictionaryObjectValue)
 0852            {
 0853                if (reader.TokenType == JsonTokenType.Null)
 0854                {
 855                    // A null JSON value is treated as a null object reference.
 0856                    AddProperty(in state.Current, dictionaryObjectValue, null);
 0857                }
 858                else
 0859                {
 0860                    JsonConverter<object> converter = GetDictionaryValueConverter<object>();
 0861                    object value = converter.Read(ref reader, typeof(object), Options)!;
 0862                    AddProperty(in state.Current, dictionaryObjectValue, value);
 0863                }
 0864            }
 0865            else if (propValue is IDictionary<string, JsonElement> dictionaryElementValue)
 0866            {
 0867                JsonConverter<JsonElement> converter = GetDictionaryValueConverter<JsonElement>();
 0868                JsonElement value = converter.Read(ref reader, typeof(JsonElement), Options);
 0869                AddProperty(in state.Current, dictionaryElementValue, value);
 0870            }
 871            else
 0872            {
 873                // Avoid a type reference to JsonObject and its converter to support trimming.
 0874                Debug.Assert(propValue is Nodes.JsonObject);
 0875                EffectiveConverter.ReadElementAndSetProperty(propValue, state.Current.JsonPropertyNameAsString!, ref rea
 0876            }
 877
 0878            return true;
 879
 880            JsonConverter<TValue> GetDictionaryValueConverter<TValue>()
 0881            {
 0882                JsonTypeInfo dictionaryValueInfo =
 0883                    JsonTypeInfo.ElementTypeInfo
 0884                    // Slower path for non-generic types that implement IDictionary<,>.
 0885                    // It is possible to cache this converter on JsonTypeInfo if we assume the property value
 0886                    // will always be the same type for all instances.
 0887                    ?? Options.GetTypeInfoInternal(typeof(TValue));
 888
 0889                Debug.Assert(dictionaryValueInfo is JsonTypeInfo<TValue>);
 0890                return ((JsonTypeInfo<TValue>)dictionaryValueInfo).EffectiveConverter;
 0891            }
 892
 893            void AddProperty<TValue>(ref readonly ReadStackFrame current, IDictionary<string, TValue> d, TValue value)
 0894            {
 0895                string property = current.JsonPropertyNameAsString!;
 0896                if (Options.AllowDuplicateProperties)
 0897                {
 0898                    d[property] = value;
 0899                }
 900                else
 0901                {
 0902                    if (!d.TryAdd(property, value))
 0903                    {
 0904                        ThrowHelper.ThrowJsonException_DuplicatePropertyNotAllowed(current.JsonPropertyInfo!);
 905                    }
 0906                }
 0907            }
 0908        }
 909
 910        internal abstract bool ReadJsonAndSetMember(object obj, scoped ref ReadStack state, ref Utf8JsonReader reader);
 911
 912        internal abstract bool ReadJsonAsObject(scoped ref ReadStack state, ref Utf8JsonReader reader, out object? value
 913
 914        internal bool ReadJsonExtensionDataValue(scoped ref ReadStack state, ref Utf8JsonReader reader, out object? valu
 0915        {
 0916            Debug.Assert(this == state.Current.JsonTypeInfo.ExtensionDataProperty);
 917
 0918            if (JsonTypeInfo.ElementType == typeof(object) && reader.TokenType == JsonTokenType.Null)
 0919            {
 0920                value = null;
 0921                return true;
 922            }
 923
 0924            JsonConverter<JsonElement> converter = (JsonConverter<JsonElement>)Options.GetConverterInternal(typeof(JsonE
 0925            if (!converter.TryRead(ref reader, typeof(JsonElement), Options, ref state, out JsonElement jsonElement, out
 0926            {
 927                // JsonElement is a struct that must be read in full.
 0928                value = null;
 0929                return false;
 930            }
 931
 0932            value = jsonElement;
 0933            return true;
 0934        }
 935
 936        internal void EnsureChildOf(JsonTypeInfo parent)
 2976937        {
 2976938            if (DeclaringTypeInfo is null)
 0939            {
 0940                DeclaringTypeInfo = parent;
 0941            }
 2976942            else if (DeclaringTypeInfo != parent)
 0943            {
 0944                ThrowHelper.ThrowInvalidOperationException_JsonPropertyInfoIsBoundToDifferentJsonTypeInfo(this);
 945            }
 946
 2976947            DeclaringTypeInfo.ResolveMatchingParameterInfo(this);
 2976948        }
 949
 950        /// <summary>
 951        /// Tries to get pre-populated value from the property if populating is enabled.
 952        /// If property value is <see langword="null"/> this method will return false.
 953        /// </summary>
 954        internal bool TryGetPrePopulatedValue(scoped ref ReadStack state)
 0955        {
 0956            if (EffectiveObjectCreationHandling != JsonObjectCreationHandling.Populate)
 0957                return false;
 958
 0959            Debug.Assert(EffectiveConverter.CanPopulate, "Property is marked with Populate but converter cannot populate
 0960            Debug.Assert(state.Parent.ReturnValue is not null, "Parent object is null");
 0961            Debug.Assert(!state.Current.IsPopulating, "We've called TryGetPrePopulatedValue more than once");
 0962            object? value = Get!(state.Parent.ReturnValue);
 0963            state.Current.ReturnValue = value;
 0964            state.Current.IsPopulating = value is not null;
 0965            return value is not null;
 0966        }
 967
 968        internal JsonTypeInfo JsonTypeInfo
 969        {
 970            get
 2976971            {
 2976972                Debug.Assert(_jsonTypeInfo?.IsConfigurationStarted == true);
 973                // Even though this instance has already been configured,
 974                // it is possible for contending threads to call the property
 975                // while the wider JsonTypeInfo graph is still being configured.
 976                // Call EnsureConfigured() to force synchronization if necessary.
 2976977                JsonTypeInfo jsonTypeInfo = _jsonTypeInfo;
 2976978                jsonTypeInfo.EnsureConfigured();
 2976979                return jsonTypeInfo;
 2976980            }
 981            set
 6614982            {
 6614983                _jsonTypeInfo = value;
 6614984            }
 985        }
 986
 987        private JsonTypeInfo? _jsonTypeInfo;
 988
 989        /// <summary>
 990        /// Returns true if <see cref="JsonTypeInfo"/> has been configured.
 991        /// This might be false even if <see cref="IsConfigured"/> is true
 992        /// in cases of recursive types or <see cref="IsIgnored"/> is true.
 993        /// </summary>
 2976994        internal bool IsPropertyTypeInfoConfigured => _jsonTypeInfo?.IsConfigured == true;
 995
 996        /// <summary>
 997        /// Property was marked JsonIgnoreCondition.Always and also hasn't been configured by the user.
 998        /// </summary>
 10099999        internal bool IsIgnored => _ignoreCondition is JsonIgnoreCondition.Always && Get is null && Set is null;
 1000
 1001        /// <summary>
 1002        /// Reflects the value of <see cref="HasGetter"/> combined with any additional global ignore policies.
 1003        /// </summary>
 71231004        internal bool CanSerialize { get; private set; }
 1005        /// <summary>
 1006        /// Reflects the value of <see cref="HasSetter"/> combined with any additional global ignore policies.
 1007        /// </summary>
 142461008        internal bool CanDeserialize { get; private set; }
 1009
 1010        /// <summary>
 1011        /// Reflects the value can be deserialized or populated
 1012        /// </summary>
 71231013        internal bool CanDeserializeOrPopulate { get; private set; }
 1014
 1015        /// <summary>
 1016        /// Relevant to source generated metadata: did the property have the <see cref="JsonIncludeAttribute"/>?
 1017        /// </summary>
 01018        internal bool SrcGen_HasJsonInclude { get; set; }
 1019
 1020        /// <summary>
 1021        /// Relevant to source generated metadata: is the property public?
 1022        /// </summary>
 01023        internal bool SrcGen_IsPublic { get; set; }
 1024
 1025        /// <summary>
 1026        /// Gets or sets the <see cref="JsonNumberHandling"/> applied to the current property.
 1027        /// </summary>
 1028        /// <exception cref="InvalidOperationException">
 1029        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 1030        /// </exception>
 1031        /// <remarks>
 1032        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 1033        /// the value of this property will be mapped from <see cref="JsonNumberHandlingAttribute"/> annotations.
 1034        /// </remarks>
 1035        public JsonNumberHandling? NumberHandling
 1036        {
 71231037            get;
 1038            set
 29761039            {
 29761040                VerifyMutable();
 29761041                field = value;
 29761042            }
 1043        }
 1044
 1045        /// <summary>
 1046        /// Number handling after considering options and declaring type number handling
 1047        /// </summary>
 295141048        internal JsonNumberHandling? EffectiveNumberHandling { get; private set; }
 1049
 1050        //  Whether the property type can be null.
 1051        internal abstract bool PropertyTypeCanBeNull { get; }
 1052
 1053        /// <summary>
 1054        /// Default value used for parameterized ctor invocation.
 1055        /// </summary>
 1056        internal abstract object? DefaultValue { get; }
 1057
 1058        /// <summary>
 1059        /// Property index on the list of JsonTypeInfo properties.
 1060        /// It is used as a unique identifier for properties.
 1061        /// It is set just before property is configured and does not change afterward.
 1062        /// It is not equivalent to index on the properties list
 1063        /// </summary>
 1064        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 1065        internal int PropertyIndex
 1066        {
 1067            get
 01068            {
 01069                Debug.Assert(IsConfigured);
 01070                return _propertyIndex;
 01071            }
 1072            set
 29761073            {
 29761074                Debug.Assert(!IsConfigured);
 29761075                _propertyIndex = value;
 29761076            }
 1077        }
 1078
 1079        private int _propertyIndex;
 1080
 1081        internal bool IsOverriddenOrShadowedBy(JsonPropertyInfo other)
 01082            => MemberName == other.MemberName && DeclaringType.IsAssignableFrom(other.DeclaringType);
 1083
 1084        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 01085        private string DebuggerDisplay => $"Name = {Name}, PropertyType = {PropertyType}";
 1086    }
 1087}
 1088

Methods/Properties

.cctor()
DeclaringTypeInfo()
EffectiveConverter()
CustomConverter()
CustomConverter(System.Text.Json.Serialization.JsonConverter)
Get()
Get(System.Func`2<System.Object,System.Object>)
Set()
Set(System.Action`2<System.Object,System.Object>)
ShouldSerialize()
ShouldSerialize(System.Func`3<System.Object,System.Object,System.Boolean>)
IgnoreCondition()
IgnoreCondition(System.Nullable`1<System.Text.Json.Serialization.JsonIgnoreCondition>)
AttributeProvider()
AttributeProvider(System.Reflection.ICustomAttributeProvider)
ObjectCreationHandling()
ObjectCreationHandling(System.Nullable`1<System.Text.Json.Serialization.JsonObjectCreationHandling>)
EffectiveObjectCreationHandling()
MemberName()
MemberType()
IsVirtual()
IsGetNullable()
IsGetNullable(System.Boolean)
IsSetNullable()
IsSetNullable(System.Boolean)
IsExtensionData()
IsExtensionData(System.Boolean)
IsRequired()
IsRequired(System.Boolean)
AssociatedParameter()
.ctor(System.Type,System.Type,System.Text.Json.Serialization.Metadata.JsonTypeInfo,System.Text.Json.JsonSerializerOptions)
GetPropertyPlaceholder()
DeclaringType()
PropertyType()
VerifyMutable()
IsConfigured()
Configure()
ValidateAndCachePropertyName()
DetermineIgnoreCondition()
DetermineSerializationCapabilities()
DetermineNumberHandlingForTypeInfo()
DetermineNumberHandlingForProperty()
DetermineEffectiveObjectCreationHandlingForProperty()
NumberHandingIsApplicable()
HasGetter()
HasSetter()
IgnoreNullTokensOnRead()
IgnoreDefaultValuesOnWrite()
IgnoreReadOnlyMember()
IsForTypeInfo()
Name()
Name(System.String)
NameAsUtf8Bytes()
EscapedNameSection()
Options()
Order()
Order(System.Int32)
ReadJsonAndAddExtensionProperty(System.Object,System.Text.Json.ReadStack&,System.Text.Json.Utf8JsonReader&)
GetDictionaryValueConverter()
AddProperty(System.Text.Json.ReadStackFrame&,System.Collections.Generic.IDictionary`2<System.String,TValue>,TValue)
ReadJsonExtensionDataValue(System.Text.Json.ReadStack&,System.Text.Json.Utf8JsonReader&,System.Object&)
EnsureChildOf(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
TryGetPrePopulatedValue(System.Text.Json.ReadStack&)
JsonTypeInfo()
JsonTypeInfo(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
IsPropertyTypeInfoConfigured()
IsIgnored()
CanSerialize()
CanDeserialize()
CanDeserializeOrPopulate()
SrcGen_HasJsonInclude()
SrcGen_IsPublic()
NumberHandling()
NumberHandling(System.Nullable`1<System.Text.Json.Serialization.JsonNumberHandling>)
EffectiveNumberHandling()
PropertyIndex()
PropertyIndex(System.Int32)
IsOverriddenOrShadowedBy(System.Text.Json.Serialization.Metadata.JsonPropertyInfo)
DebuggerDisplay()