< Summary

Line coverage
37%
Covered lines: 330
Uncovered lines: 539
Coverable lines: 869
Total lines: 2062
Line coverage: 37.9%
Branch coverage
30%
Covered branches: 114
Total branches: 372
Branch coverage: 30.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
File 1: .ctor(...)100%11100%
File 1: GetProperty(...)0%26260%
File 1: UpdateUtf8PropertyCache(...)0%440%
File 2: .ctor(...)100%11100%
File 2: SetPolymorphismOptions(...)0%220%
File 2: MakeReadOnly()100%11100%
File 2: .ctor(...)100%110%
File 2: OnCollectionModifying()100%110%
File 2: SetUnionDeconstructor(...)0%220%
File 2: SetUnionConstructor(...)0%220%
File 2: ValidateCanBeUsedForPropertyMetadataSerialization()0%220%
File 2: VerifyMutable()50%2266.66%
File 2: EnsureConfigured()100%22100%
File 2: ConfigureSynchronized()66.66%6677.27%
File 2: Configure()66.66%242472.09%
File 2: ValidateUnionContract()0%660%
File 2: CacheUnionNullableCaseType()0%440%
File 2: ConfigureTypeClassifier()0%12120%
File 2: BuildUnionValueTypeMap(...)0%880%
File 2: AddUnionValueTypes(System.Text.Json.Serialization.JsonValueType,System.Type,System.Collections.Generic.Dictionary`2<System.Text.Json.Serialization.JsonValueType,System.Type>,System.Text.Json.Serialization.JsonValueType&)0%660%
File 2: DetermineIsCompatibleWithCurrentOptions()72.22%181860.71%
File 2: IsCurrentNodeCompatible()50%4466.66%
File 2: DetermineUsesParameterizedConstructor()100%22100%
File 2: CreateJsonTypeInfo(...)100%110%
File 2: CreateJsonTypeInfo(...)0%220%
File 2: CreateJsonTypeInfo(...)50%2257.14%
File 2: CreateJsonPropertyInfo(...)0%220%
File 2: CreatePropertyUsingReflection(...)75%44100%
File 2: .ctor(...)50%22100%
File 2: GetHashCode()100%11100%
File 2: Equals(...)50%22100%
File 2: Equals(...)0%220%
File 2: ConfigureProperties()39.28%282868.42%
File 2: PopulateParameterInfoValues(...)100%22100%
File 2: ResolveMatchingParameterInfo(...)62.5%88100%
File 2: ConfigureConstructorParameters()58.33%121264.51%
File 2: ValidateType(...)50%2260%
File 2: IsInvalidForSerialization(...)50%88100%
File 2: MapInterfaceTypesToCallbacks()71.42%141445.45%
File 2: SetCreateObjectIfCompatible(...)100%44100%
File 2: IsByRefLike(...)100%11100%
File 2: IsValidExtensionDataProperty(...)0%10100%
File 2: GetTypeInfoKind(...)50%181873.33%
File 2: .ctor(...)100%11100%
File 2: OnCollectionModifying()50%4477.77%
File 2: ValidateAddedValue(...)100%11100%
File 2: SortProperties()100%110%
File 2: AddPropertyWithConflictResolution(...)11.11%181829.72%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.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.Runtime.CompilerServices;
 7
 8namespace System.Text.Json.Serialization.Metadata
 9{
 10    public abstract partial class JsonTypeInfo
 11    {
 12        // The number of parameters the deserialization constructor has. If this is not equal to ParameterCache.Count, t
 13        // that not all parameters are bound to object properties, and an exception will be thrown if deserialization is
 99914        internal int ParameterCount { get; private protected set; }
 15
 16        // All of the serializable parameters on a POCO constructor
 17        internal ReadOnlySpan<JsonParameterInfo> ParameterCache
 18        {
 19            get
 020            {
 021                Debug.Assert(IsConfigured && _parameterCache is not null);
 022                return _parameterCache;
 023            }
 24        }
 25
 26        internal bool UsesParameterizedConstructor
 27        {
 28            get
 4429            {
 4430                Debug.Assert(IsConfigured);
 4431                return _parameterCache is not null;
 4432            }
 33        }
 34
 35        private JsonParameterInfo[]? _parameterCache;
 36
 37        // All of the serializable properties on a POCO (minus the extension property).
 38        internal ReadOnlySpan<JsonPropertyInfo> PropertyCache
 39        {
 40            get
 041            {
 042                Debug.Assert(IsConfigured && _propertyCache is not null);
 043                return _propertyCache;
 044            }
 45        }
 46
 47        private JsonPropertyInfo[]? _propertyCache;
 48
 49        // All of the serializable properties on a POCO (minus the extension property) keyed on property name.
 50        internal Dictionary<string, JsonPropertyInfo> PropertyIndex
 51        {
 52            get
 053            {
 054                Debug.Assert(IsConfigured && _propertyIndex is not null);
 055                return _propertyIndex;
 056            }
 57        }
 58
 59        private Dictionary<string, JsonPropertyInfo>? _propertyIndex;
 60
 61        /// <summary>
 62        /// Stores a cache of UTF-8 encoded property names and their associated JsonPropertyInfo, if available.
 63        /// Consulted before the <see cref="PropertyIndex" /> lookup to avoid added allocations and decoding costs.
 64        /// The cache is grown on-demand appending encountered unbounded properties or alternative casings.
 65        /// </summary>
 414766        private PropertyRef[] _utf8PropertyCache = [];
 67
 68        /// <summary>
 69        /// Defines the core property lookup logic for a given unescaped UTF-8 encoded property name.
 70        /// </summary>
 71        internal JsonPropertyInfo? GetProperty(ReadOnlySpan<byte> propertyName, ref ReadStackFrame frame, out byte[] utf
 072        {
 073            Debug.Assert(IsConfigured);
 74
 75            // The logic can be broken up into roughly three stages:
 76            // 1. Look up the UTF-8 property cache for potential exact matches in the encoding.
 77            // 2. If no match is found, decode to UTF-16 and look up the primary dictionary.
 78            // 3. Store the new result for potential inclusion to the UTF-8 cache once deserialization is complete.
 79
 080            PropertyRef[] utf8PropertyCache = _utf8PropertyCache; // Keep a local copy of the cache in case it changes b
 081            ReadOnlySpan<PropertyRef> utf8PropertyCacheSpan = utf8PropertyCache;
 082            ulong key = PropertyRef.GetKey(propertyName);
 83
 084            if (!utf8PropertyCacheSpan.IsEmpty)
 085            {
 86                PropertyRef propertyRef;
 87
 88                // Start with the current property index, and then go forwards\backwards.
 089                int propertyIndex = frame.PropertyIndex;
 90
 091                int count = utf8PropertyCacheSpan.Length;
 092                int iForward = Math.Min(propertyIndex, count);
 093                int iBackward = iForward - 1;
 94
 095                while (true)
 096                {
 097                    if (iForward < count)
 098                    {
 099                        propertyRef = utf8PropertyCacheSpan[iForward];
 0100                        if (propertyRef.Equals(propertyName, key))
 0101                        {
 0102                            utf8PropertyName = propertyRef.Utf8PropertyName;
 0103                            return propertyRef.Info;
 104                        }
 105
 0106                        ++iForward;
 107
 0108                        if (iBackward >= 0)
 0109                        {
 0110                            propertyRef = utf8PropertyCacheSpan[iBackward];
 0111                            if (propertyRef.Equals(propertyName, key))
 0112                            {
 0113                                utf8PropertyName = propertyRef.Utf8PropertyName;
 0114                                return propertyRef.Info;
 115                            }
 116
 0117                            --iBackward;
 0118                        }
 0119                    }
 0120                    else if (iBackward >= 0)
 0121                    {
 0122                        propertyRef = utf8PropertyCacheSpan[iBackward];
 0123                        if (propertyRef.Equals(propertyName, key))
 0124                        {
 0125                            utf8PropertyName = propertyRef.Utf8PropertyName;
 0126                            return propertyRef.Info;
 127                        }
 128
 0129                        --iBackward;
 0130                    }
 131                    else
 0132                    {
 133                        // Property was not found.
 0134                        break;
 135                    }
 0136                }
 0137            }
 138
 139            // No cached item was found. Try the main dictionary which has all of the properties.
 0140            if (PropertyIndex.TryLookupUtf8Key(propertyName, out JsonPropertyInfo? info) &&
 0141                (!Options.PropertyNameCaseInsensitive || propertyName.SequenceEqual(info.NameAsUtf8Bytes)))
 0142            {
 143                // We have an exact match in UTF8 encoding.
 0144                utf8PropertyName = info.NameAsUtf8Bytes;
 0145            }
 146            else
 0147            {
 148                // Make a copy of the original Span.
 0149                utf8PropertyName = propertyName.ToArray();
 0150            }
 151
 152            // Assuming there is capacity, store the new result for potential
 153            // inclusion to the UTF-8 cache once deserialization is complete.
 154
 0155            ref PropertyRefCacheBuilder? cacheBuilder = ref frame.PropertyRefCacheBuilder;
 0156            if ((cacheBuilder?.TotalCount ?? utf8PropertyCache.Length) < PropertyRefCacheBuilder.MaxCapacity)
 0157            {
 0158                (cacheBuilder ??= new(utf8PropertyCache)).TryAdd(new(key, info, utf8PropertyName));
 0159            }
 160
 0161            return info;
 0162        }
 163
 164        /// <summary>
 165        /// Attempts to update the UTF-8 property cache with the results gathered in the current deserialization operati
 166        /// The update operation is done optimistically and results are discarded if the cache was updated by another th
 167        /// </summary>
 168        internal void UpdateUtf8PropertyCache(ref ReadStackFrame frame)
 0169        {
 0170            Debug.Assert(frame.PropertyRefCacheBuilder is { Count: > 0 });
 171
 0172            PropertyRef[]? currentCache = _utf8PropertyCache;
 0173            PropertyRefCacheBuilder cacheBuilder = frame.PropertyRefCacheBuilder;
 174
 0175            if (currentCache == cacheBuilder.OriginalCache)
 0176            {
 0177                PropertyRef[] newCache = cacheBuilder.ToArray();
 0178                Debug.Assert(newCache.Length <= PropertyRefCacheBuilder.MaxCapacity);
 0179                _utf8PropertyCache = newCache;
 0180            }
 181
 0182            frame.PropertyRefCacheBuilder = null;
 0183        }
 184    }
 185}
 186

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.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;
 5using System.Collections.Generic;
 6using System.ComponentModel;
 7using System.Diagnostics;
 8using System.Diagnostics.CodeAnalysis;
 9using System.IO;
 10using System.IO.Pipelines;
 11using System.Reflection;
 12using System.Runtime.CompilerServices;
 13using System.Runtime.ExceptionServices;
 14using System.Text.Json.Reflection;
 15using System.Text.Json.Serialization.Converters;
 16using System.Threading;
 17using System.Threading.Tasks;
 18
 19namespace System.Text.Json.Serialization.Metadata
 20{
 21    /// <summary>
 22    /// Provides JSON serialization-related metadata about a type.
 23    /// </summary>
 24    [DebuggerDisplay("{DebuggerDisplay,nq}")]
 25    public abstract partial class JsonTypeInfo
 26    {
 27        internal const string MetadataFactoryRequiresUnreferencedCode = "JSON serialization and deserialization might re
 28
 29        internal const string JsonObjectTypeName = "System.Text.Json.Nodes.JsonObject";
 30
 31        internal delegate T ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>(TArg0? arg0, TArg1? arg1, TA
 32
 33        /// <summary>
 34        /// Negated bitmask of the required properties, indexed by <see cref="JsonPropertyInfo.PropertyIndex"/>.
 35        /// </summary>
 49636        internal BitArray? OptionalPropertiesMask { get; private set; }
 037        internal bool ShouldTrackRequiredProperties => OptionalPropertiesMask is not null;
 38
 414739        internal JsonTypeInfo(Type type, JsonConverter converter, JsonSerializerOptions options)
 414740        {
 414741            Type = type;
 414742            Options = options;
 414743            Converter = converter;
 414744            Kind = GetTypeInfoKind(type, converter);
 414745            PropertyInfoForTypeInfo = CreatePropertyInfoForTypeInfo();
 414746            ElementType = converter.ElementType;
 414747            KeyType = converter.KeyType;
 414748        }
 49
 50        /// <summary>
 51        /// Gets the element type corresponding to an enumerable, dictionary or optional type.
 52        /// </summary>
 53        /// <remarks>
 54        /// Returns the element type for enumerable types, the value type for dictionary types,
 55        /// and the underlying type for <see cref="Nullable{T}"/> or F# optional types.
 56        ///
 57        /// Returns <see langword="null"/> for all other types or types using custom converters.
 58        /// </remarks>
 461659        public Type? ElementType { get; }
 60
 61        /// <summary>
 62        /// Gets the key type corresponding to a dictionary type.
 63        /// </summary>
 64        /// <remarks>
 65        /// Returns the key type for dictionary types.
 66        ///
 67        /// Returns <see langword="null"/> for all other types or types using custom converters.
 68        /// </remarks>
 441869        public Type? KeyType { get; }
 70
 71        /// <summary>
 72        /// Gets or sets a parameterless factory to be used on deserialization.
 73        /// </summary>
 74        /// <exception cref="InvalidOperationException">
 75        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 76        ///
 77        /// -or-
 78        ///
 79        /// A parameterless factory is not supported for the current metadata <see cref="Kind"/>.
 80        /// </exception>
 81        /// <remarks>
 82        /// If set to <see langword="null" />, any attempt to deserialize instances of the given type will result in an 
 83        ///
 84        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 85        /// types with a single default constructor or default constructors annotated with <see cref="JsonConstructorAtt
 86        /// will be mapped to this delegate.
 87        /// </remarks>
 88        public Func<object>? CreateObject
 89        {
 302590            get => _createObject;
 91            set
 092            {
 093                SetCreateObject(value);
 094            }
 95        }
 96
 97        private protected abstract void SetCreateObject(Delegate? createObject);
 98        private protected Func<object>? _createObject;
 99
 4233100        internal Func<object>? CreateObjectForExtensionDataProperty { get; set; }
 101
 102        /// <summary>
 103        /// Gets or sets a callback to be invoked before serialization occurs.
 104        /// </summary>
 105        /// <exception cref="InvalidOperationException">
 106        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 107        ///
 108        /// -or-
 109        ///
 110        /// Serialization callbacks are only supported for <see cref="JsonTypeInfoKind.Object"/> metadata.
 111        /// </exception>
 112        /// <remarks>
 113        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 114        /// the value of this callback will be mapped from any <see cref="IJsonOnSerializing"/> implementation on the ty
 115        /// </remarks>
 116        public Action<object>? OnSerializing
 117        {
 0118            get;
 119            set
 0120            {
 0121                VerifyMutable();
 122
 0123                if (Kind is not (JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary))
 0124                {
 0125                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 126                }
 127
 0128                field = value;
 0129            }
 130        }
 131
 132        /// <summary>
 133        /// Gets or sets a callback to be invoked after serialization occurs.
 134        /// </summary>
 135        /// <exception cref="InvalidOperationException">
 136        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 137        ///
 138        /// -or-
 139        ///
 140        /// Serialization callbacks are only supported for <see cref="JsonTypeInfoKind.Object"/> metadata.
 141        /// </exception>
 142        /// <remarks>
 143        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 144        /// the value of this callback will be mapped from any <see cref="IJsonOnSerialized"/> implementation on the typ
 145        /// </remarks>
 146        public Action<object>? OnSerialized
 147        {
 0148            get;
 149            set
 0150            {
 0151                VerifyMutable();
 152
 0153                if (Kind is not (JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary))
 0154                {
 0155                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 156                }
 157
 0158                field = value;
 0159            }
 160        }
 161
 162        /// <summary>
 163        /// Gets or sets a callback to be invoked before deserialization occurs.
 164        /// </summary>
 165        /// <exception cref="InvalidOperationException">
 166        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 167        ///
 168        /// -or-
 169        ///
 170        /// Serialization callbacks are only supported for <see cref="JsonTypeInfoKind.Object"/> metadata.
 171        /// </exception>
 172        /// <remarks>
 173        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 174        /// the value of this callback will be mapped from any <see cref="IJsonOnDeserializing"/> implementation on the 
 175        /// </remarks>
 176        public Action<object>? OnDeserializing
 177        {
 14178            get;
 179            set
 0180            {
 0181                VerifyMutable();
 182
 0183                if (Kind is not (JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary))
 0184                {
 0185                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 186                }
 187
 0188                if (Converter.IsConvertibleCollection)
 0189                {
 190                    // The values for convertible collections aren't available at the start of deserialization.
 0191                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOnDeserializingCallbacksNotSupported(Type);
 192                }
 193
 0194                field = value;
 0195            }
 196        }
 197
 198        /// <summary>
 199        /// Gets or sets a callback to be invoked after deserialization occurs.
 200        /// </summary>
 201        /// <exception cref="InvalidOperationException">
 202        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 203        ///
 204        /// -or-
 205        ///
 206        /// Serialization callbacks are only supported for <see cref="JsonTypeInfoKind.Object"/> metadata.
 207        /// </exception>
 208        /// <remarks>
 209        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 210        /// the value of this callback will be mapped from any <see cref="IJsonOnDeserialized"/> implementation on the t
 211        /// </remarks>
 212        public Action<object>? OnDeserialized
 213        {
 0214            get;
 215            set
 0216            {
 0217                VerifyMutable();
 218
 0219                if (Kind is not (JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary))
 0220                {
 0221                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 222                }
 223
 0224                field = value;
 0225            }
 226        }
 227
 228        /// <summary>
 229        /// Gets the list of <see cref="JsonPropertyInfo"/> metadata corresponding to the current type.
 230        /// </summary>
 231        /// <remarks>
 232        /// Property is only applicable to metadata of kind <see cref="JsonTypeInfoKind.Object"/>.
 233        /// For other kinds an empty, read-only list will be returned.
 234        ///
 235        /// The order of <see cref="JsonPropertyInfo"/> entries in the list determines the serialization order,
 236        /// unless either of the entries specifies a non-zero <see cref="JsonPropertyInfo.Order"/> value,
 237        /// in which case the properties will be stable sorted by <see cref="JsonPropertyInfo.Order"/>.
 238        ///
 239        /// It is required that added <see cref="JsonPropertyInfo"/> entries are unique up to <see cref="JsonPropertyInf
 240        /// however this will only be validated on serialization, once the metadata instance gets locked for further mod
 241        /// </remarks>
 0242        public IList<JsonPropertyInfo> Properties => PropertyList;
 243
 244        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 245        internal JsonPropertyInfoList PropertyList
 246        {
 247            get
 3472248            {
 3472249                return _properties ?? CreatePropertyList();
 250                JsonPropertyInfoList CreatePropertyList()
 496251                {
 496252                    var list = new JsonPropertyInfoList(this);
 496253                    if (_sourceGenDelayedPropertyInitializer is { } propInit)
 0254                    {
 255                        // .NET 6 source gen backward compatibility -- ensure that the
 256                        // property initializer delegate is invoked lazily.
 0257                        JsonMetadataServices.PopulateProperties(this, list, propInit);
 0258                    }
 259
 496260                    JsonPropertyInfoList? result = Interlocked.CompareExchange(ref _properties, list, null);
 496261                    _sourceGenDelayedPropertyInitializer = null;
 496262                    return result ?? list;
 496263                }
 3472264            }
 265        }
 266
 267        /// <summary>
 268        /// Stores the .NET 6-style property initialization delegate for delayed evaluation.
 269        /// </summary>
 270        internal Func<JsonSerializerContext, JsonPropertyInfo[]>? SourceGenDelayedPropertyInitializer
 271        {
 272            get => _sourceGenDelayedPropertyInitializer;
 273            set
 0274            {
 0275                Debug.Assert(!IsReadOnly);
 0276                Debug.Assert(_properties is null, "must not be set if a property list has been initialized.");
 0277                _sourceGenDelayedPropertyInitializer = value;
 0278            }
 279        }
 280
 281        private Func<JsonSerializerContext, JsonPropertyInfo[]>? _sourceGenDelayedPropertyInitializer;
 282        private JsonPropertyInfoList? _properties;
 283
 284        /// <summary>
 285        /// Gets or sets a configuration object specifying polymorphism metadata.
 286        /// </summary>
 287        /// <exception cref="ArgumentException">
 288        /// <paramref name="value" /> has been associated with a different <see cref="JsonTypeInfo"/> instance.
 289        /// </exception>
 290        /// <exception cref="InvalidOperationException">
 291        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 292        ///
 293        /// -or-
 294        ///
 295        /// Polymorphic serialization is not supported for the current metadata <see cref="Kind"/>.
 296        /// </exception>
 297        /// <remarks>
 298        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 299        /// the configuration of this setting will be mapped from any <see cref="JsonDerivedTypeAttribute"/> or <see cre
 300        /// </remarks>
 301        public JsonPolymorphismOptions? PolymorphismOptions
 302        {
 8294303            get => _polymorphismOptions;
 304            set
 0305            {
 0306                VerifyMutable();
 307
 0308                if (value is not null)
 0309                {
 0310                    if (Kind == JsonTypeInfoKind.None)
 0311                    {
 0312                        ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 313                    }
 314
 0315                    if (value.DeclaringTypeInfo is not null && value.DeclaringTypeInfo != this)
 0316                    {
 0317                        ThrowHelper.ThrowArgumentException_JsonPolymorphismOptionsAssociatedWithDifferentJsonTypeInfo(na
 318                    }
 319
 0320                    value.DeclaringTypeInfo = this;
 0321                }
 322
 0323                _polymorphismOptions = value;
 0324            }
 325        }
 326
 327        internal void SetPolymorphismOptions(JsonPolymorphismOptions options)
 0328        {
 0329            Debug.Assert(!IsReadOnly);
 0330            Debug.Assert(options.DeclaringTypeInfo is null || options.DeclaringTypeInfo == this);
 331
 0332            options.DeclaringTypeInfo = this;
 0333            _polymorphismOptions = options;
 0334        }
 335
 336        /// <summary>
 337        /// Specifies whether the current instance has been locked for modification.
 338        /// </summary>
 339        /// <remarks>
 340        /// A <see cref="JsonTypeInfo"/> instance can be locked either if
 341        /// it has been passed to one of the <see cref="JsonSerializer"/> methods,
 342        /// has been associated with a <see cref="JsonSerializerContext"/> instance,
 343        /// or a user explicitly called the <see cref="MakeReadOnly"/> method on the instance.
 344        /// </remarks>
 64500345        public bool IsReadOnly { get; private set; }
 346
 347        /// <summary>
 348        /// Locks the current instance for further modification.
 349        /// </summary>
 350        /// <remarks>This method is idempotent.</remarks>
 8294351        public void MakeReadOnly() => IsReadOnly = true;
 352
 353        private protected JsonPolymorphismOptions? _polymorphismOptions;
 354
 355        /// <summary>
 356        /// Gets the list of union case type metadata for this type.
 357        /// </summary>
 358        /// <remarks>
 359        /// <para>
 360        /// This property is only meaningful when <see cref="Kind"/> is <see cref="JsonTypeInfoKind.Union"/>.
 361        /// The list is mutable during configuration and frozen at finalization time.
 362        /// </para>
 363        /// <para>
 364        /// For types recognized as unions via <c>System.Runtime.CompilerServices.UnionAttribute</c>,
 365        /// the list is automatically populated. For contract customization, users can
 366        /// populate this list manually.
 367        /// </para>
 368        /// </remarks>
 0369        public IList<JsonUnionCaseInfo> UnionCases => UnionCaseList;
 370
 371        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 372        internal JsonUnionCaseInfoList UnionCaseList
 373        {
 374            get
 0375            {
 0376                return _unionCases ?? CreateUnionCaseList();
 377                JsonUnionCaseInfoList CreateUnionCaseList()
 0378                {
 0379                    var list = new JsonUnionCaseInfoList(this);
 0380                    JsonUnionCaseInfoList? result = Interlocked.CompareExchange(ref _unionCases, list, null);
 0381                    return result ?? list;
 0382                }
 0383            }
 384        }
 385
 386        private JsonUnionCaseInfoList? _unionCases;
 387
 388        internal sealed class JsonUnionCaseInfoList : ConfigurationList<JsonUnionCaseInfo>
 389        {
 390            private readonly JsonTypeInfo _parent;
 391
 0392            public JsonUnionCaseInfoList(JsonTypeInfo parent, IEnumerable<JsonUnionCaseInfo>? source = null) : base(sour
 0393            {
 0394                _parent = parent;
 0395            }
 396
 0397            public override bool IsReadOnly => _parent.IsReadOnly;
 0398            protected override void OnCollectionModifying() => _parent.VerifyMutable();
 399        }
 400
 401        /// <summary>
 402        /// Gets or sets the delegate that classifies JSON payloads to determine the target type
 403        /// during deserialization.
 404        /// </summary>
 405        /// <remarks>
 406        /// <para>
 407        /// This is the shared classification property for both polymorphic types and union types.
 408        /// </para>
 409        /// <para>
 410        /// For <strong>polymorphic types</strong>: when set, bypasses the standard discriminator-based
 411        /// type resolution (scanning for a <c>$type</c> property). When <see langword="null"/>
 412        /// (default), the existing discriminator-based approach is used unchanged.
 413        /// </para>
 414        /// <para>
 415        /// For <strong>union types</strong>: determines which case type matches the JSON payload.
 416        /// When set by the user, replaces the default token-based matching.
 417        /// </para>
 418        /// </remarks>
 419        public JsonTypeClassifier? TypeClassifier
 420        {
 421            get
 0422            {
 0423                if (_typeClassifierResolutionPending)
 0424                {
 0425                    ConfigureTypeClassifier();
 0426                }
 427
 0428                return _typeClassifier;
 0429            }
 430            set
 0431            {
 0432                VerifyMutable();
 433                // Explicit user assignment wins; discard any pending factory.
 0434                _typeClassifier = value;
 0435                _typeClassifierFactory = null;
 0436                _typeClassifierResolutionPending = false;
 0437            }
 438        }
 439
 440        private JsonTypeClassifier? _typeClassifier;
 441
 442        /// <summary>
 443        /// Gets or sets the weakly-typed delegate that deconstructs a union instance into
 444        /// its case type and case value.
 445        /// </summary>
 446        /// <remarks>
 447        /// <para>
 448        /// The delegate combines object classification and value extraction in a single call,
 449        /// returning a tuple of <c>(Type? CaseType, object? CaseValue)</c>.
 450        /// </para>
 451        /// <para>
 452        /// <c>CaseType</c> doubles as the discriminator for the union's null state:
 453        /// </para>
 454        /// <list type="bullet">
 455        ///   <item>
 456        ///     <description>
 457        ///       A non-<see langword="null"/> <c>CaseType</c> instructs the converter to serialize
 458        ///       <c>CaseValue</c> using the <see cref="JsonTypeInfo"/> registered for that case
 459        ///       type. <c>CaseValue</c> may be <see langword="null"/>, in which case the JSON
 460        ///       output is <c>null</c> rendered through that case type's contract (this preserves
 461        ///       per-case null annotations). The <c>CaseType</c> must be one of the union's
 462        ///       declared case types; returning a runtime type that is more derived than any
 463        ///       declared case violates STJ contract invariants.
 464        ///     </description>
 465        ///   </item>
 466        ///   <item>
 467        ///     <description>
 468        ///       A <see langword="null"/> <c>CaseType</c> signals that the instance is the
 469        ///       canonical null union value. The converter writes JSON <c>null</c> directly,
 470        ///       bypassing all per-case contracts; <c>CaseValue</c> is ignored.
 471        ///     </description>
 472        ///   </item>
 473        /// </list>
 474        /// <para>
 475        /// Prefer setting the strongly-typed <see cref="JsonTypeInfo{T}.UnionDeconstructor"/>
 476        /// on <see cref="JsonTypeInfo{T}"/> to avoid boxing when the union type is a value type.
 477        /// </para>
 478        /// </remarks>
 479        public Func<object, (Type? CaseType, object? CaseValue)>? UnionDeconstructor
 480        {
 0481            get => _unionDeconstructor;
 482            set
 0483            {
 0484                VerifyMutable();
 0485                SetUnionDeconstructor(value);
 0486            }
 487        }
 488
 489        private protected virtual void SetUnionDeconstructor(Delegate? deconstructor)
 0490        {
 0491            Debug.Assert(deconstructor is null or Func<object, (Type?, object?)>);
 0492            _unionDeconstructor = (Func<object, (Type?, object?)>?)deconstructor;
 0493        }
 494
 495        private protected Func<object, (Type?, object?)>? _unionDeconstructor;
 496
 497        /// <summary>
 498        /// Gets or sets the weakly-typed delegate that constructs a union instance from
 499        /// a case type and case value.
 500        /// </summary>
 501        /// <remarks>
 502        /// <para>
 503        /// The delegate takes a <see cref="Type"/> parameter naming the resolved case type
 504        /// (as produced by classification) and an <c>object?</c> case value, returning the
 505        /// constructed union instance. The <c>caseType</c> parameter is always non-<see langword="null"/>
 506        /// and disambiguates among overlapping case types (e.g., <c>Labrador : Dog</c>).
 507        /// </para>
 508        /// <para>
 509        /// The delegate also encapsulates the union's null-handling policy. When the
 510        /// converter encounters a JSON <see cref="JsonTokenType.Null"/> token, it bypasses
 511        /// any configured <see cref="TypeClassifier"/> and invokes the delegate with a
 512        /// <see langword="null"/> case value. Implementations should produce the canonical
 513        /// null-holding union instance when at least one case is nullable, and otherwise
 514        /// throw a <see cref="JsonException"/>. On the null path the <c>caseType</c> argument
 515        /// is set to one of the declared nullable case types but its specific value should
 516        /// be ignored; per union semantics, all nullable cases collapse to the same null
 517        /// instance.
 518        /// </para>
 519        /// <para>
 520        /// Prefer setting the strongly-typed <see cref="JsonTypeInfo{T}.UnionConstructor"/>
 521        /// on <see cref="JsonTypeInfo{T}"/> to avoid boxing when the union type is a value type.
 522        /// </para>
 523        /// </remarks>
 524        public Func<Type, object?, object>? UnionConstructor
 525        {
 0526            get => _unionConstructor;
 527            set
 0528            {
 0529                VerifyMutable();
 0530                SetUnionConstructor(value);
 0531            }
 532        }
 533
 534        private protected virtual void SetUnionConstructor(Delegate? constructor)
 0535        {
 0536            Debug.Assert(constructor is null or Func<Type, object?, object>);
 0537            _unionConstructor = (Func<Type, object?, object>?)constructor;
 0538        }
 539
 540        private protected Func<Type, object?, object>? _unionConstructor;
 541
 542        /// <summary>
 543        /// Pre-built JSON value shape to type map for default union deserialization (no custom classifier).
 544        /// Maps each <see cref="JsonValueType"/> to the first-declared case type that
 545        /// serializes as that value shape. Populated at configuration time from <see cref="UnionCases"/>.
 546        /// </summary>
 0547        internal Dictionary<JsonValueType, Type>? UnionValueTypeMap { get; set; }
 548
 549        /// <summary>
 550        /// Bitmask of <see cref="JsonValueType"/> shapes that two or more declared case types both
 551        /// serialize as. Populated alongside <see cref="UnionValueTypeMap"/>; used at deserialize
 552        /// time to surface a precise "ambiguous case" error when one of these value shapes appears.
 553        /// <see cref="JsonValueType.None"/> means no ambiguous shapes were detected.
 554        /// </summary>
 0555        internal JsonValueType UnionAmbiguousValueTypes { get; set; }
 556
 557        /// <summary>
 558        /// First nullable union case type, if any. Populated at configuration time from <see cref="UnionCases"/>.
 559        /// </summary>
 0560        internal Type? UnionNullableCaseType { get; set; }
 561
 562        /// <summary>
 563        /// Optional per-type factory captured during metadata creation (resolver phase)
 564        /// from <see cref="JsonUnionAttribute.TypeClassifier"/> or <see cref="JsonPolymorphicAttribute.TypeClassifier"/
 565        /// </summary>
 566        internal JsonTypeClassifierFactory? TypeClassifierFactory
 567        {
 0568            get => _typeClassifierFactory;
 569            set
 0570            {
 0571                Debug.Assert(!IsReadOnly);
 0572                _typeClassifierFactory = value;
 0573            }
 574        }
 575
 576        /// <summary>
 577        /// Indicates whether type classifier resolution should run lazily from the
 578        /// <see cref="TypeClassifier"/> getter or during metadata configuration.
 579        /// </summary>
 580        internal bool TypeClassifierResolutionPending
 581        {
 582            get => _typeClassifierResolutionPending;
 583            set
 0584            {
 0585                Debug.Assert(!IsReadOnly);
 0586                _typeClassifierResolutionPending = value;
 0587            }
 588        }
 589
 590        private JsonTypeClassifierFactory? _typeClassifierFactory;
 591        private volatile bool _typeClassifierResolutionPending;
 592
 3941593        internal object? CreateObjectWithArgs { get; set; }
 594
 595        // Add method delegate for non-generic Stack and Queue; and types that derive from them.
 0596        internal object? AddMethodDelegate { get; set; }
 597
 1325598        internal JsonPropertyInfo? ExtensionDataProperty { get; private set; }
 599
 46412600        internal PolymorphicTypeResolver? PolymorphicTypeResolver { get; private set; }
 601
 602        // Indicates that SerializeHandler is populated.
 4147603        internal bool HasSerializeHandler { get; private protected set; }
 604
 605        // Indicates that SerializeHandler is populated and is compatible with the associated contract metadata.
 4147606        internal bool CanUseSerializeHandler { get; private set; }
 607
 608        // Configure would normally have thrown why initializing properties for source gen but type had SerializeHandler
 609        // so it is allowed to be used for fast-path serialization but it will throw if used for metadata-based serializ
 0610        internal bool PropertyMetadataSerializationNotSupported { get; set; }
 611
 496612        internal bool IsNullable => Converter.NullableElementConverter is not null;
 613        internal bool CanBeNull => PropertyInfoForTypeInfo.PropertyTypeCanBeNull;
 614
 615        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 616        internal void ValidateCanBeUsedForPropertyMetadataSerialization()
 0617        {
 0618            if (PropertyMetadataSerializationNotSupported)
 0619            {
 0620                ThrowHelper.ThrowInvalidOperationException_NoMetadataForTypeProperties(Options.TypeInfoResolver, Type);
 621            }
 0622        }
 623
 624        /// <summary>
 625        /// Return the JsonTypeInfo for the element type, or null if the type is not an enumerable or dictionary.
 626        /// </summary>
 627        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 628        internal JsonTypeInfo? ElementTypeInfo
 629        {
 630            get
 30631            {
 30632                Debug.Assert(IsConfigured);
 30633                Debug.Assert(_elementTypeInfo is null or { IsConfigurationStarted: true });
 634                // Even though this instance has already been configured,
 635                // it is possible for contending threads to call the property
 636                // while the wider JsonTypeInfo graph is still being configured.
 637                // Call EnsureConfigured() to force synchronization if necessary.
 30638                JsonTypeInfo? elementTypeInfo = _elementTypeInfo;
 30639                elementTypeInfo?.EnsureConfigured();
 30640                return elementTypeInfo;
 30641            }
 642            set
 0643            {
 0644                Debug.Assert(!IsReadOnly);
 0645                Debug.Assert(value is null || value.Type == ElementType);
 0646                _elementTypeInfo = value;
 0647            }
 648        }
 649
 650        /// <summary>
 651        /// Return the JsonTypeInfo for the key type, or null if the type is not a dictionary.
 652        /// </summary>
 653        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 654        internal JsonTypeInfo? KeyTypeInfo
 655        {
 656            get
 12657            {
 12658                Debug.Assert(IsConfigured);
 12659                Debug.Assert(_keyTypeInfo is null or { IsConfigurationStarted: true });
 660                // Even though this instance has already been configured,
 661                // it is possible for contending threads to call the property
 662                // while the wider JsonTypeInfo graph is still being configured.
 663                // Call EnsureConfigured() to force synchronization if necessary.
 12664                JsonTypeInfo? keyTypeInfo = _keyTypeInfo;
 12665                keyTypeInfo?.EnsureConfigured();
 12666                return keyTypeInfo;
 12667            }
 668            set
 0669            {
 0670                Debug.Assert(!IsReadOnly);
 0671                Debug.Assert(value is null || value.Type == KeyType);
 0672                _keyTypeInfo = value;
 0673            }
 674        }
 675
 676        private JsonTypeInfo? _elementTypeInfo;
 677        private JsonTypeInfo? _keyTypeInfo;
 678
 679        /// <summary>
 680        /// Gets the <see cref="JsonSerializerOptions"/> value associated with the current <see cref="JsonTypeInfo" /> i
 681        /// </summary>
 133847682        public JsonSerializerOptions Options { get; }
 683
 684        /// <summary>
 685        /// Gets the <see cref="Type"/> for which the JSON serialization contract is being defined.
 686        /// </summary>
 60736687        public Type Type { get; }
 688
 689        /// <summary>
 690        /// Gets the <see cref="JsonConverter"/> associated with the current type.
 691        /// </summary>
 692        /// <remarks>
 693        /// The <see cref="JsonConverter"/> associated with the type determines the value of <see cref="Kind"/>,
 694        /// and by extension the types of metadata that are configurable in the current JSON contract.
 695        /// As such, the value of the converter cannot be changed once a <see cref="JsonTypeInfo"/> instance has been cr
 696        /// </remarks>
 15850697        public JsonConverter Converter { get; }
 698
 699        /// <summary>
 700        /// Determines the kind of contract metadata that the current instance is specifying.
 701        /// </summary>
 702        /// <remarks>
 703        /// The value of <see cref="Kind"/> determines what aspects of the JSON contract are configurable.
 704        /// For example, it is only possible to configure the <see cref="Properties"/> list for metadata
 705        /// of kind <see cref="JsonTypeInfoKind.Object"/>.
 706        ///
 707        /// The value of <see cref="Kind"/> is determined exclusively by the <see cref="JsonConverter"/>
 708        /// resolved for the current type, and cannot be changed once resolution has happened.
 709        /// User-defined custom converters (specified either via <see cref="JsonConverterAttribute"/> or <see cref="Json
 710        /// are metadata-agnostic and thus always resolve to <see cref="JsonTypeInfoKind.None"/>.
 711        /// </remarks>
 57206712        public JsonTypeInfoKind Kind { get; }
 713
 714        /// <summary>
 715        /// Dummy <see cref="JsonPropertyInfo"/> instance corresponding to the declaring type of this <see cref="JsonTyp
 716        /// </summary>
 717        /// <remarks>
 718        /// Used as convenience in cases where we want to serialize property-like values that do not define property met
 719        /// 1. a collection element type,
 720        /// 2. a dictionary key or value type or,
 721        /// 3. the property metadata for the root-level value.
 722        /// For example, for a property returning <see cref="List{T}"/> where T is a string,
 723        /// a JsonTypeInfo will be created with .Type=typeof(string) and .PropertyInfoForTypeInfo=JsonPropertyInfo{strin
 724        /// </remarks>
 27367725        internal JsonPropertyInfo PropertyInfoForTypeInfo { get; }
 726
 727        private protected abstract JsonPropertyInfo CreatePropertyInfoForTypeInfo();
 728
 729        /// <summary>
 730        /// Gets or sets the type-level <see cref="JsonSerializerOptions.NumberHandling"/> override.
 731        /// </summary>
 732        /// <exception cref="InvalidOperationException">
 733        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 734        /// </exception>
 735        /// <exception cref="ArgumentOutOfRangeException">
 736        /// Specified an invalid <see cref="JsonNumberHandling"/> value.
 737        /// </exception>
 738        /// <remarks>
 739        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 740        /// the value of this callback will be mapped from any <see cref="JsonNumberHandlingAttribute"/> annotations.
 741        /// </remarks>
 742        public JsonNumberHandling? NumberHandling
 743        {
 8715744            get => _numberHandling;
 745            set
 0746            {
 0747                VerifyMutable();
 748
 0749                if (value is not null && !JsonSerializer.IsValidNumberHandlingValue(value.Value))
 0750                {
 0751                    throw new ArgumentOutOfRangeException(nameof(value));
 752                }
 753
 0754                _numberHandling = value;
 0755            }
 756        }
 757
 0758        internal JsonNumberHandling EffectiveNumberHandling => _numberHandling ?? Options.NumberHandling;
 759        private JsonNumberHandling? _numberHandling;
 760
 761        /// <summary>
 762        /// Gets or sets the type-level <see cref="JsonUnmappedMemberHandling"/> override.
 763        /// </summary>
 764        /// <exception cref="InvalidOperationException">
 765        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 766        ///
 767        /// -or-
 768        ///
 769        /// Unmapped member handling only supported for <see cref="JsonTypeInfoKind.Object"/>.
 770        /// </exception>
 771        /// <exception cref="ArgumentOutOfRangeException">
 772        /// Specified an invalid <see cref="JsonUnmappedMemberHandling"/> value.
 773        /// </exception>
 774        /// <remarks>
 775        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 776        /// the value of this callback will be mapped from any <see cref="JsonUnmappedMemberHandlingAttribute"/> annotat
 777        /// </remarks>
 778        public JsonUnmappedMemberHandling? UnmappedMemberHandling
 779        {
 496780            get;
 781            set
 0782            {
 0783                VerifyMutable();
 784
 0785                if (Kind != JsonTypeInfoKind.Object)
 0786                {
 0787                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 788                }
 789
 0790                if (value is not null && !JsonSerializer.IsValidUnmappedMemberHandlingValue(value.Value))
 0791                {
 0792                    throw new ArgumentOutOfRangeException(nameof(value));
 793                }
 794
 0795                field = value;
 0796            }
 797        }
 798
 496799        internal JsonUnmappedMemberHandling EffectiveUnmappedMemberHandling { get; private set; }
 800
 801        /// <summary>
 802        /// Gets or sets the preferred <see cref="JsonObjectCreationHandling"/> value for properties contained in the ty
 803        /// </summary>
 804        /// <exception cref="InvalidOperationException">
 805        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 806        ///
 807        /// -or-
 808        ///
 809        /// Unmapped member handling only supported for <see cref="JsonTypeInfoKind.Object"/>.
 810        /// </exception>
 811        /// <exception cref="ArgumentOutOfRangeException">
 812        /// Specified an invalid <see cref="JsonObjectCreationHandling"/> value.
 813        /// </exception>
 814        /// <remarks>
 815        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 816        /// the value of this callback will be mapped from <see cref="JsonObjectCreationHandlingAttribute"/> annotations
 817        /// </remarks>
 818        public JsonObjectCreationHandling? PreferredPropertyObjectCreationHandling
 819        {
 7123820            get;
 821            set
 0822            {
 0823                VerifyMutable();
 824
 0825                if (Kind != JsonTypeInfoKind.Object)
 0826                {
 0827                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 828                }
 829
 0830                if (value is not null && !JsonSerializer.IsValidCreationHandlingValue(value.Value))
 0831                {
 0832                    throw new ArgumentOutOfRangeException(nameof(value));
 833                }
 834
 0835                field = value;
 0836            }
 837        }
 838
 839        /// <summary>
 840        /// Gets or sets the <see cref="IJsonTypeInfoResolver"/> from which this metadata instance originated.
 841        /// </summary>
 842        /// <exception cref="InvalidOperationException">
 843        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 844        /// </exception>
 845        /// <remarks>
 846        /// Metadata used to determine the <see cref="JsonSerializerContext.GeneratedSerializerOptions"/>
 847        /// configuration for the current metadata instance.
 848        /// </remarks>
 849        [EditorBrowsable(EditorBrowsableState.Never)]
 850        public IJsonTypeInfoResolver? OriginatingResolver
 851        {
 0852            get;
 853            set
 4147854            {
 4147855                VerifyMutable();
 856
 4147857                if (value is JsonSerializerContext)
 0858                {
 859                    // The source generator uses this property setter to brand the metadata instance as user-unmodified.
 860                    // Even though users could call the same property setter to unset this flag, this is generally speak
 861                    // This flag is only used to determine fast-path invalidation, worst case scenario this would lead t
 0862                    IsCustomized = false;
 0863                }
 864
 4147865                field = value;
 4147866            }
 867        }
 868
 869        /// <summary>
 870        /// Gets or sets an attribute provider corresponding to the deserialization constructor.
 871        /// </summary>
 872        /// <exception cref="InvalidOperationException">
 873        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 874        /// </exception>
 875        /// <remarks>
 876        /// When resolving metadata via the built-in resolvers this will be populated with
 877        /// the underlying <see cref="ConstructorInfo" /> of the serialized property or field.
 878        /// </remarks>
 879        public ICustomAttributeProvider? ConstructorAttributeProvider
 880        {
 881            get
 0882            {
 0883                Func<ICustomAttributeProvider>? ctorAttrProviderFactory = Volatile.Read(ref ConstructorAttributeProvider
 0884                ICustomAttributeProvider? ctorAttrProvider = _constructorAttributeProvider;
 885
 0886                if (ctorAttrProvider is null && ctorAttrProviderFactory is not null)
 0887                {
 0888                    _constructorAttributeProvider = ctorAttrProvider = ctorAttrProviderFactory();
 0889                    Volatile.Write(ref ConstructorAttributeProviderFactory, null);
 0890                }
 891
 0892                return ctorAttrProvider;
 0893            }
 894            internal set
 1128895            {
 1128896                Debug.Assert(!IsReadOnly);
 897
 1128898                _constructorAttributeProvider = value;
 1128899                Volatile.Write(ref ConstructorAttributeProviderFactory, null);
 1128900            }
 901        }
 902
 903        // Metadata emanating from the source generator use delayed attribute provider initialization
 904        // ensuring that reflection metadata resolution remains pay-for-play and is trimmable.
 905        internal Func<ICustomAttributeProvider>? ConstructorAttributeProviderFactory;
 906        private ICustomAttributeProvider? _constructorAttributeProvider;
 907
 908        internal void VerifyMutable()
 33351909        {
 33351910            if (IsReadOnly)
 0911            {
 0912                ThrowHelper.ThrowInvalidOperationException_TypeInfoImmutable();
 913            }
 914
 33351915            IsCustomized = true;
 33351916        }
 917
 918        /// <summary>
 919        /// Indicates that the current JsonTypeInfo might contain user modifications.
 920        /// Defaults to true, and is only unset by the built-in contract resolvers.
 921        /// </summary>
 45792922        internal bool IsCustomized { get; set; } = true;
 923
 61227924        internal bool IsConfigured => _configurationState == ConfigurationState.Configured;
 3018925        internal bool IsConfigurationStarted => _configurationState is not ConfigurationState.NotConfigured;
 926        private volatile ConfigurationState _configurationState;
 927        private enum ConfigurationState : byte
 928        {
 929            NotConfigured = 0,
 930            Configuring = 1,
 931            Configured = 2
 932        };
 933
 934        private ExceptionDispatchInfo? _cachedConfigureError;
 935
 936        internal void EnsureConfigured()
 23689937        {
 23689938            if (!IsConfigured)
 8294939                ConfigureSynchronized();
 940
 941            void ConfigureSynchronized()
 8294942            {
 8294943                Options.MakeReadOnly();
 8294944                MakeReadOnly();
 945
 8294946                _cachedConfigureError?.Throw();
 947
 8294948                lock (Options.CacheContext)
 8294949                {
 8294950                    if (_configurationState != ConfigurationState.NotConfigured)
 4147951                    {
 952                        // The value of _configurationState is either
 953                        //    'Configuring': recursive instance configured by this thread or
 954                        //    'Configured' : instance already configured by another thread.
 955                        // We can safely yield the configuration operation in both cases.
 4147956                        return;
 957                    }
 958
 4147959                    _cachedConfigureError?.Throw();
 960
 961                    try
 4147962                    {
 4147963                        _configurationState = ConfigurationState.Configuring;
 4147964                        Configure();
 4147965                        _configurationState = ConfigurationState.Configured;
 4147966                    }
 0967                    catch (Exception e)
 0968                    {
 0969                        _cachedConfigureError = ExceptionDispatchInfo.Capture(e);
 0970                        _configurationState = ConfigurationState.NotConfigured;
 0971                        throw;
 972                    }
 4147973                }
 8294974            }
 23689975        }
 976
 977        private void Configure()
 4147978        {
 4147979            Debug.Assert(Monitor.IsEntered(Options.CacheContext), "Configure called directly, use EnsureConfigured which
 4147980            Debug.Assert(Options.IsReadOnly);
 4147981            Debug.Assert(IsReadOnly);
 982
 4147983            PropertyInfoForTypeInfo.Configure();
 984
 4147985            if (PolymorphismOptions is not null)
 0986            {
 987                // This needs to be done before ConfigureProperties() is called
 988                // JsonPropertyInfo.Configure() must have this value available in order to detect Polymoprhic + cyclic c
 0989                PolymorphicTypeResolver = new PolymorphicTypeResolver(Options, PolymorphismOptions, Type, Converter.CanH
 0990                ConfigureTypeClassifier();
 0991            }
 992
 4147993            if (Kind == JsonTypeInfoKind.Object)
 496994            {
 496995                ConfigureProperties();
 996
 496997                if (DetermineUsesParameterizedConstructor())
 333998                {
 333999                    ConfigureConstructorParameters();
 3331000                }
 4961001            }
 1002
 41471003            if (ElementType != null)
 4691004            {
 4691005                _elementTypeInfo ??= Options.GetTypeInfoInternal(ElementType);
 4691006                _elementTypeInfo.EnsureConfigured();
 4691007            }
 1008
 41471009            if (KeyType != null)
 2711010            {
 2711011                _keyTypeInfo ??= Options.GetTypeInfoInternal(KeyType);
 2711012                _keyTypeInfo.EnsureConfigured();
 2711013            }
 1014
 41471015            DetermineIsCompatibleWithCurrentOptions();
 41471016            CanUseSerializeHandler = HasSerializeHandler && IsCompatibleWithCurrentOptions;
 1017
 1018            // Validate union metadata before sealing. By this point, every modifier has run
 1019            // and any contract customization that the user wanted to apply has been applied,
 1020            // so the final shape of the JsonTypeInfo can be checked authoritatively.
 41471021            if (Kind is JsonTypeInfoKind.Union)
 01022            {
 01023                ValidateUnionContract();
 01024                CacheUnionNullableCaseType();
 01025                ConfigureTypeClassifier();
 01026            }
 1027
 1028            // Build the union dispatch map after modifiers have had a chance to install
 1029            // a custom TypeClassifier. The classifier path bypasses the value-shape map entirely.
 41471030            if (Kind is JsonTypeInfoKind.Union &&
 41471031                _typeClassifier is null &&
 41471032                UnionCases.Count > 0)
 01033            {
 01034                BuildUnionValueTypeMap(UnionCases, Options, this);
 01035            }
 41471036        }
 1037
 1038        /// <summary>
 1039        /// Validates that a union <see cref="JsonTypeInfo"/> has a well-formed shape after
 1040        /// all modifiers have run: at least one declared case, plus both the constructor
 1041        /// and the deconstructor delegates.
 1042        /// </summary>
 1043        private void ValidateUnionContract()
 01044        {
 01045            Debug.Assert(Kind is JsonTypeInfoKind.Union);
 1046
 01047            if (UnionCases.Count == 0)
 01048            {
 01049                ThrowHelper.ThrowInvalidOperationException_UnionCasesNotPopulated(Type);
 1050            }
 1051
 01052            if (UnionConstructor is null)
 01053            {
 01054                ThrowHelper.ThrowInvalidOperationException_UnionCannotCreateValue(Type);
 1055            }
 1056
 01057            if (UnionDeconstructor is null)
 01058            {
 01059                ThrowHelper.ThrowInvalidOperationException_UnionCannotReadValue(Type);
 1060            }
 01061        }
 1062
 1063        private void CacheUnionNullableCaseType()
 01064        {
 01065            Debug.Assert(Kind is JsonTypeInfoKind.Union);
 1066
 01067            foreach (JsonUnionCaseInfo unionCase in UnionCases)
 01068            {
 01069                if (unionCase.IsNullable)
 01070                {
 01071                    UnionNullableCaseType = unionCase.CaseType;
 01072                    return;
 1073                }
 01074            }
 1075
 01076            UnionNullableCaseType = null;
 01077        }
 1078
 1079        private void ConfigureTypeClassifier()
 01080        {
 01081            Debug.Assert(Kind is JsonTypeInfoKind.Union || PolymorphismOptions is not null);
 1082
 1083            // The classifier factory may throw, which is fine --
 1084            // If invoked by the getter ahead of configure we rethrow directly,
 1085            // but if invoked by the configuration pipeline it captures and caches the exception.
 1086
 01087            JsonTypeClassifierFactory? factory = Volatile.Read(ref _typeClassifierFactory);
 01088            if (!_typeClassifierResolutionPending)
 01089            {
 01090                return;
 1091            }
 1092
 1093            JsonTypeClassifierContext ctx;
 01094            if (Kind is JsonTypeInfoKind.Union)
 01095            {
 01096                Debug.Assert(UnionCases.Count > 0);
 01097                ctx = new JsonTypeClassifierContext(
 01098                    JsonTypeClassifierKind.Union,
 01099                    this,
 01100                    new List<JsonUnionCaseInfo>(UnionCases),
 01101                    Array.Empty<JsonDerivedType>(),
 01102                    typeDiscriminatorPropertyName: null);
 01103            }
 1104            else
 01105            {
 01106                JsonPolymorphismOptions? polymorphismOptions = PolymorphismOptions;
 01107                Debug.Assert(polymorphismOptions is not null);
 1108
 01109                ctx = new JsonTypeClassifierContext(
 01110                    JsonTypeClassifierKind.PolymorphicType,
 01111                    this,
 01112                    Array.Empty<JsonUnionCaseInfo>(),
 01113                    new List<JsonDerivedType>(polymorphismOptions.DerivedTypes),
 01114                    polymorphismOptions.TypeDiscriminatorPropertyName);
 01115            }
 1116
 01117            if (factory is not null)
 01118            {
 01119                if (!factory.CanClassify(ctx))
 01120                {
 01121                    ThrowHelper.ThrowInvalidOperationException_TypeClassifierNotSupported(factory.GetType(), Type);
 1122                }
 01123            }
 1124            else
 01125            {
 01126                factory = Options.GetTypeClassifierFromList(ctx);
 01127            }
 1128
 01129            if (factory is not null)
 01130            {
 01131                JsonTypeClassifier classifier = factory.CreateJsonClassifier(ctx, Options);
 01132                Interlocked.CompareExchange(ref _typeClassifier, classifier, null);
 01133            }
 1134
 01135            _typeClassifierFactory = null;
 01136            _typeClassifierResolutionPending = false;
 01137        }
 1138
 1139        /// <summary>
 1140        /// Builds the union dispatch metadata: a value-shape-to-type map for default deserialization
 1141        /// plus diagnostic state for cases that cannot be unambiguously classified by value shape.
 1142        /// </summary>
 1143        /// <remarks>
 1144        /// <para>
 1145        /// This helper is intentionally lenient at configuration time so that union types are
 1146        /// always serializable (serialization is driven by <see cref="UnionDeconstructor"/> and
 1147        /// doesn't need the value-shape map). Diagnostic state is recorded on the type info and
 1148        /// surfaced as a <see cref="JsonException"/> only at deserialization time when a token
 1149        /// is actually encountered that cannot be unambiguously routed to a single case.
 1150        /// </para>
 1151        /// <para>
 1152        /// Each case is categorized by its supported JSON value shapes via
 1153        /// <see cref="JsonConverter.GetSupportedJsonValueTypes"/>. User-defined converters
 1154        /// are conservatively classified as potentially representing every JSON value shape.
 1155        /// </para>
 1156        /// <para>
 1157        /// This helper operates purely on already-resolved <see cref="JsonTypeInfo"/> /
 1158        /// <see cref="JsonConverter"/> metadata and does not perform any reflection, so it is
 1159        /// safe to call from the trim-safe configuration pipeline.
 1160        /// </para>
 1161        /// </remarks>
 1162        private static void BuildUnionValueTypeMap(IList<JsonUnionCaseInfo> unionCases, JsonSerializerOptions options, J
 01163        {
 01164            var map = new Dictionary<JsonValueType, Type>();
 01165            JsonValueType ambiguousValueTypes = JsonValueType.None;
 1166
 01167            foreach (JsonUnionCaseInfo info in unionCases)
 01168            {
 01169                Type caseType = info.CaseType;
 01170                JsonTypeInfo caseTypeInfo = options.GetTypeInfoInternal(caseType);
 01171                JsonConverter converter = caseTypeInfo.Converter;
 01172                if (converter.ConverterStrategy is ConverterStrategy.Union)
 01173                {
 01174                    continue;
 1175                }
 1176
 01177                JsonNumberHandling effectiveNumberHandling =
 01178                    target.NumberHandling ?? caseTypeInfo.NumberHandling ?? options.NumberHandling;
 01179                JsonValueType valueTypes = converter.GetSupportedJsonValueTypes(effectiveNumberHandling);
 1180
 01181                AddUnionValueTypes(valueTypes, caseType, map, ref ambiguousValueTypes);
 01182            }
 1183
 01184            target.UnionValueTypeMap = map;
 01185            target.UnionAmbiguousValueTypes = ambiguousValueTypes;
 1186
 1187            static void AddUnionValueTypes(
 1188                JsonValueType valueTypes,
 1189                Type caseType,
 1190                Dictionary<JsonValueType, Type> map,
 1191                ref JsonValueType ambiguousValueTypes)
 01192            {
 01193                ReadOnlySpan<JsonValueType> allValueTypes =
 01194                [
 01195                    JsonValueType.Object,
 01196                    JsonValueType.Array,
 01197                    JsonValueType.String,
 01198                    JsonValueType.Number,
 01199                    JsonValueType.Boolean,
 01200                ];
 1201
 01202                foreach (JsonValueType valueType in allValueTypes)
 01203                {
 01204                    if ((valueTypes & valueType) == 0)
 01205                    {
 01206                        continue;
 1207                    }
 1208
 01209                    if (!map.TryAdd(valueType, caseType))
 01210                    {
 1211                        // Two declared cases share this JSON value shape. First-wins for the dispatch
 1212                        // map (so unrelated values still deserialize), but record the ambiguity
 1213                        // so deserialize-time can throw a precise error if this shape shows up.
 01214                        ambiguousValueTypes |= valueType;
 01215                    }
 01216                }
 01217            }
 01218        }
 1219
 1220        /// <summary>
 1221        /// Gets any ancestor polymorphic types that declare
 1222        /// a type discriminator for the current type. Consulted
 1223        /// when serializing polymorphic values as objects.
 1224        /// </summary>
 1225        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 1226        internal JsonTypeInfo? AncestorPolymorphicType
 1227        {
 1228            get
 01229            {
 01230                Debug.Assert(IsConfigured);
 01231                Debug.Assert(Type != typeof(object));
 1232
 01233                if (!_isAncestorPolymorphicTypeResolved)
 01234                {
 01235                    _ancestorPolymorhicType = PolymorphicTypeResolver.FindNearestPolymorphicBaseType(this);
 01236                    _isAncestorPolymorphicTypeResolved = true;
 01237                }
 1238
 01239                return _ancestorPolymorhicType;
 01240            }
 1241        }
 1242
 1243        private JsonTypeInfo? _ancestorPolymorhicType;
 1244        private volatile bool _isAncestorPolymorphicTypeResolved;
 1245
 1246        /// <summary>
 1247        /// Determines if the transitive closure of all JsonTypeInfo metadata referenced
 1248        /// by the current type (property types, key types, element types, ...) are
 1249        /// compatible with the settings as specified in JsonSerializerOptions.
 1250        /// </summary>
 1251        private void DetermineIsCompatibleWithCurrentOptions()
 41471252        {
 1253            // Defines a recursive algorithm validating that the `IsCurrentNodeCompatible`
 1254            // predicate is valid for every node in the type graph. This method only checks
 1255            // the immediate children, with recursion being driven by the Configure() method.
 1256            // Therefore, this method must be called _after_ the child nodes have been configured.
 1257
 41471258            Debug.Assert(IsReadOnly);
 41471259            Debug.Assert(!IsConfigured);
 1260
 41471261            if (!IsCurrentNodeCompatible())
 01262            {
 01263                IsCompatibleWithCurrentOptions = false;
 01264                return;
 1265            }
 1266
 41471267            if (_properties is not null)
 4961268            {
 74401269                foreach (JsonPropertyInfo property in _properties)
 29761270                {
 29761271                    Debug.Assert(property.IsConfigured);
 1272
 29761273                    if (!property.IsPropertyTypeInfoConfigured)
 01274                    {
 1275                        // Either an ignored property or property is part of a cycle.
 1276                        // In both cases we can ignore these instances.
 01277                        continue;
 1278                    }
 1279
 29761280                    if (!property.JsonTypeInfo.IsCompatibleWithCurrentOptions)
 01281                    {
 01282                        IsCompatibleWithCurrentOptions = false;
 01283                        return;
 1284                    }
 29761285                }
 4961286            }
 1287
 41471288            if (_elementTypeInfo?.IsCompatibleWithCurrentOptions == false ||
 41471289                _keyTypeInfo?.IsCompatibleWithCurrentOptions == false)
 01290            {
 01291                IsCompatibleWithCurrentOptions = false;
 01292                return;
 1293            }
 1294
 41471295            Debug.Assert(IsCompatibleWithCurrentOptions);
 1296
 1297            // Defines the core predicate that must be checked for every node in the type graph.
 1298            bool IsCurrentNodeCompatible()
 41471299            {
 41471300                if (IsCustomized)
 01301                {
 1302                    // Return false if we have detected contract customization by the user.
 01303                    return false;
 1304                }
 1305
 41471306                if (Options.CanUseFastPathSerializationLogic)
 41471307                {
 1308                    // Simple case/backward compatibility: options uses a combination of compatible built-in converters.
 41471309                    return true;
 1310                }
 1311
 01312                return OriginatingResolver.IsCompatibleWithOptions(Options);
 41471313            }
 41471314        }
 1315
 1316        /// <summary>
 1317        /// Holds the result of the above algorithm -- NB must default to true
 1318        /// to establish a base case for recursive types and any JsonIgnored property types.
 1319        /// </summary>
 120101320        private bool IsCompatibleWithCurrentOptions { get; set; } = true;
 1321
 1322        /// <summary>
 1323        /// Determine if the current configuration is compatible with using a parameterized constructor.
 1324        /// </summary>
 1325        internal bool DetermineUsesParameterizedConstructor()
 79521326            => Converter.ConstructorIsParameterized && CreateObject is null;
 1327
 1328        /// <summary>
 1329        /// Creates a blank <see cref="JsonTypeInfo{T}"/> instance.
 1330        /// </summary>
 1331        /// <typeparam name="T">The type for which contract metadata is specified.</typeparam>
 1332        /// <param name="options">The <see cref="JsonSerializerOptions"/> instance the metadata is associated with.</par
 1333        /// <returns>A blank <see cref="JsonTypeInfo{T}"/> instance.</returns>
 1334        /// <exception cref="ArgumentNullException"><paramref name="options"/> is null.</exception>
 1335        /// <remarks>
 1336        /// The returned <see cref="JsonTypeInfo{T}"/> will be blank, with the exception of the
 1337        /// <see cref="Converter"/> property which will be resolved either from
 1338        /// <see cref="JsonSerializerOptions.Converters"/> or the built-in converters for the type.
 1339        /// Any converters specified via <see cref="JsonConverterAttribute"/> on the type declaration
 1340        /// will not be resolved by this method.
 1341        ///
 1342        /// What converter does get resolved influences the value of <see cref="Kind"/>,
 1343        /// which constrains the type of metadata that can be modified in the <see cref="JsonTypeInfo"/> instance.
 1344        /// </remarks>
 1345        [RequiresUnreferencedCode(MetadataFactoryRequiresUnreferencedCode)]
 1346        [RequiresDynamicCode(MetadataFactoryRequiresUnreferencedCode)]
 1347        public static JsonTypeInfo<T> CreateJsonTypeInfo<T>(JsonSerializerOptions options)
 01348        {
 01349            ArgumentNullException.ThrowIfNull(options);
 1350
 01351            JsonConverter converter = DefaultJsonTypeInfoResolver.GetConverterForType(typeof(T), options, resolveJsonCon
 01352            return new JsonTypeInfo<T>(converter, options);
 01353        }
 1354
 1355        /// <summary>
 1356        /// Creates a blank <see cref="JsonTypeInfo"/> instance.
 1357        /// </summary>
 1358        /// <param name="type">The type for which contract metadata is specified.</param>
 1359        /// <param name="options">The <see cref="JsonSerializerOptions"/> instance the metadata is associated with.</par
 1360        /// <returns>A blank <see cref="JsonTypeInfo"/> instance.</returns>
 1361        /// <exception cref="ArgumentNullException"><paramref name="type"/> or <paramref name="options"/> is null.</exce
 1362        /// <exception cref="ArgumentException"><paramref name="type"/> cannot be used for serialization.</exception>
 1363        /// <remarks>
 1364        /// The returned <see cref="JsonTypeInfo"/> will be blank, with the exception of the
 1365        /// <see cref="Converter"/> property which will be resolved either from
 1366        /// <see cref="JsonSerializerOptions.Converters"/> or the built-in converters for the type.
 1367        /// Any converters specified via <see cref="JsonConverterAttribute"/> on the type declaration
 1368        /// will not be resolved by this method.
 1369        ///
 1370        /// What converter does get resolved influences the value of <see cref="Kind"/>,
 1371        /// which constrains the type of metadata that can be modified in the <see cref="JsonTypeInfo"/> instance.
 1372        /// </remarks>
 1373        [RequiresUnreferencedCode(MetadataFactoryRequiresUnreferencedCode)]
 1374        [RequiresDynamicCode(MetadataFactoryRequiresUnreferencedCode)]
 1375        public static JsonTypeInfo CreateJsonTypeInfo(Type type, JsonSerializerOptions options)
 01376        {
 01377            ArgumentNullException.ThrowIfNull(type);
 01378            ArgumentNullException.ThrowIfNull(options);
 1379
 01380            if (IsInvalidForSerialization(type))
 01381            {
 01382                ThrowHelper.ThrowArgumentException_CannotSerializeInvalidType(nameof(type), type, null, null);
 1383            }
 1384
 01385            JsonConverter converter = DefaultJsonTypeInfoResolver.GetConverterForType(type, options, resolveJsonConverte
 01386            return CreateJsonTypeInfo(type, converter, options);
 01387        }
 1388
 1389        [RequiresUnreferencedCode(MetadataFactoryRequiresUnreferencedCode)]
 1390        [RequiresDynamicCode(MetadataFactoryRequiresUnreferencedCode)]
 1391        internal static JsonTypeInfo CreateJsonTypeInfo(Type type, JsonConverter converter, JsonSerializerOptions option
 41471392        {
 1393            JsonTypeInfo jsonTypeInfo;
 1394
 41471395            if (converter.Type == type)
 41471396            {
 1397                // For performance, avoid doing a reflection-based instantiation
 1398                // if the converter type matches that of the declared type.
 41471399                jsonTypeInfo = converter.CreateJsonTypeInfo(options);
 41471400            }
 1401            else
 01402            {
 01403                Type jsonTypeInfoType = typeof(JsonTypeInfo<>).MakeGenericType(type);
 01404                jsonTypeInfo = (JsonTypeInfo)jsonTypeInfoType.CreateInstanceNoWrapExceptions(
 01405                    parameterTypes: [typeof(JsonConverter), typeof(JsonSerializerOptions)],
 01406                    parameters: new object[] { converter, options })!;
 01407            }
 1408
 41471409            Debug.Assert(jsonTypeInfo.Type == type);
 41471410            return jsonTypeInfo;
 41471411        }
 1412
 1413        /// <summary>
 1414        /// Creates a blank <see cref="JsonPropertyInfo"/> instance for the current <see cref="JsonTypeInfo"/>.
 1415        /// </summary>
 1416        /// <param name="propertyType">The declared type for the property.</param>
 1417        /// <param name="name">The property name used in JSON serialization and deserialization.</param>
 1418        /// <returns>A blank <see cref="JsonPropertyInfo"/> instance.</returns>
 1419        /// <exception cref="ArgumentNullException"><paramref name="propertyType"/> or <paramref name="name"/> is null.<
 1420        /// <exception cref="ArgumentException"><paramref name="propertyType"/> cannot be used for serialization.</excep
 1421        /// <exception cref="InvalidOperationException">The <see cref="JsonTypeInfo"/> instance has been locked for furt
 1422        [RequiresUnreferencedCode(MetadataFactoryRequiresUnreferencedCode)]
 1423        [RequiresDynamicCode(MetadataFactoryRequiresUnreferencedCode)]
 1424        public JsonPropertyInfo CreateJsonPropertyInfo(Type propertyType, string name)
 01425        {
 01426            ArgumentNullException.ThrowIfNull(propertyType);
 01427            ArgumentNullException.ThrowIfNull(name);
 1428
 01429            if (IsInvalidForSerialization(propertyType))
 01430            {
 01431                ThrowHelper.ThrowArgumentException_CannotSerializeInvalidType(nameof(propertyType), propertyType, Type, 
 1432            }
 1433
 01434            VerifyMutable();
 01435            JsonPropertyInfo propertyInfo = CreatePropertyUsingReflection(propertyType, declaringType: null);
 01436            propertyInfo.Name = name;
 1437
 01438            return propertyInfo;
 01439        }
 1440
 1441        [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 1442        [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 1443        internal JsonPropertyInfo CreatePropertyUsingReflection(Type propertyType, Type? declaringType)
 29761444        {
 1445            JsonPropertyInfo jsonPropertyInfo;
 1446
 29761447            if (Options.TryGetTypeInfoCached(propertyType, out JsonTypeInfo? jsonTypeInfo))
 24671448            {
 1449                // If a JsonTypeInfo has already been cached for the property type,
 1450                // avoid reflection-based initialization by delegating construction
 1451                // of JsonPropertyInfo<T> construction to the property type metadata.
 24671452                jsonPropertyInfo = jsonTypeInfo.CreateJsonPropertyInfo(declaringTypeInfo: this, declaringType, Options);
 24671453            }
 1454            else
 5091455            {
 1456                // Metadata for `propertyType` has not been registered yet.
 1457                // Use reflection to instantiate the correct JsonPropertyInfo<T>
 5091458                Type propertyInfoType = typeof(JsonPropertyInfo<>).MakeGenericType(propertyType);
 5091459                jsonPropertyInfo = (JsonPropertyInfo)propertyInfoType.CreateInstanceNoWrapExceptions(
 5091460                    parameterTypes: [typeof(Type), typeof(JsonTypeInfo), typeof(JsonSerializerOptions)],
 5091461                    parameters: new object[] { declaringType ?? Type, this, Options })!;
 5091462            }
 1463
 29761464            Debug.Assert(jsonPropertyInfo.PropertyType == propertyType);
 29761465            return jsonPropertyInfo;
 29761466        }
 1467
 1468        /// <summary>
 1469        /// Creates a JsonPropertyInfo whose property type matches the type of this JsonTypeInfo instance.
 1470        /// </summary>
 1471        private protected abstract JsonPropertyInfo CreateJsonPropertyInfo(JsonTypeInfo declaringTypeInfo, Type? declari
 1472
 1473        private protected Dictionary<ParameterLookupKey, JsonParameterInfoValues>? _parameterInfoValuesIndex;
 1474
 1475        // Untyped, root-level serialization methods
 1476        internal abstract void SerializeAsObject(Utf8JsonWriter writer, object? rootValue);
 1477        internal abstract Task<FlushResult> SerializeAsObjectAsync(PipeWriter pipeWriter, object? rootValue, int flushTh
 1478        internal abstract Task SerializeAsObjectAsync(Stream utf8Json, object? rootValue, CancellationToken cancellation
 1479        internal abstract Task SerializeAsObjectAsync(PipeWriter utf8Json, object? rootValue, CancellationToken cancella
 1480        internal abstract void SerializeAsObject(Stream utf8Json, object? rootValue);
 1481
 1482        // Untyped, root-level deserialization methods
 1483        internal abstract object? DeserializeAsObject(ref Utf8JsonReader reader, ref ReadStack state);
 1484        internal abstract ValueTask<object?> DeserializeAsObjectAsync(PipeReader utf8Json, CancellationToken cancellatio
 1485        internal abstract ValueTask<object?> DeserializeAsObjectAsync(Stream utf8Json, CancellationToken cancellationTok
 1486        internal abstract object? DeserializeAsObject(Stream utf8Json);
 1487
 1488        internal ref struct PropertyHierarchyResolutionState(JsonSerializerOptions options)
 1489        {
 4961490            public Dictionary<string, (JsonPropertyInfo, int index)> AddedProperties = new(options.PropertyNameCaseInsen
 1491            public Dictionary<string, JsonPropertyInfo>? IgnoredProperties;
 1492            public bool IsPropertyOrderSpecified;
 1493        }
 1494
 1495        private protected readonly struct ParameterLookupKey(Type type, string name) : IEquatable<ParameterLookupKey>
 1496        {
 99901497            public Type Type { get; } = type;
 159841498            public string Name { get; } = name;
 59941499            public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Name);
 19981500            public bool Equals(ParameterLookupKey other) => Type == other.Type && string.Equals(Name, other.Name, String
 01501            public override bool Equals([NotNullWhen(true)] object? obj) => obj is ParameterLookupKey key && Equals(key)
 1502        }
 1503
 1504        internal void ConfigureProperties()
 4961505        {
 4961506            Debug.Assert(Kind == JsonTypeInfoKind.Object);
 4961507            Debug.Assert(_propertyCache is null);
 4961508            Debug.Assert(_propertyIndex is null);
 4961509            Debug.Assert(ExtensionDataProperty is null);
 1510
 4961511            JsonPropertyInfoList properties = PropertyList;
 4961512            StringComparer comparer = Options.PropertyNameCaseInsensitive ? StringComparer.OrdinalIgnoreCase : StringCom
 4961513            Dictionary<string, JsonPropertyInfo> propertyIndex = new(properties.Count, comparer);
 4961514            List<JsonPropertyInfo> propertyCache = new(properties.Count);
 1515
 4961516            bool arePropertiesSorted = true;
 4961517            int previousPropertyOrder = int.MinValue;
 4961518            BitArray? requiredPropertiesMask = null;
 1519
 69441520            for (int i = 0; i < properties.Count; i++)
 29761521            {
 29761522                JsonPropertyInfo property = properties[i];
 29761523                Debug.Assert(property.DeclaringTypeInfo == this);
 1524
 29761525                if (property.IsExtensionData)
 01526                {
 01527                    if (UnmappedMemberHandling is JsonUnmappedMemberHandling.Disallow)
 01528                    {
 01529                        ThrowHelper.ThrowInvalidOperationException_ExtensionDataConflictsWithUnmappedMemberHandling(Type
 1530                    }
 1531
 01532                    if (ExtensionDataProperty is not null)
 01533                    {
 01534                        ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(Type, typeof(Json
 1535                    }
 1536
 01537                    ExtensionDataProperty = property;
 01538                }
 1539                else
 29761540                {
 29761541                    property.PropertyIndex = i;
 1542
 29761543                    if (property.IsRequired)
 01544                    {
 01545                        (requiredPropertiesMask ??= new BitArray(properties.Count))[i] = true;
 01546                    }
 1547
 29761548                    if (arePropertiesSorted)
 29761549                    {
 29761550                        arePropertiesSorted = previousPropertyOrder <= property.Order;
 29761551                        previousPropertyOrder = property.Order;
 29761552                    }
 1553
 29761554                    if (!propertyIndex.TryAdd(property.Name, property))
 01555                    {
 01556                        ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, property.Name);
 1557                    }
 1558
 29761559                    propertyCache.Add(property);
 29761560                }
 1561
 29761562                property.Configure();
 29761563            }
 1564
 4961565            if (!arePropertiesSorted)
 01566            {
 1567                // Properties have been configured by the user and require sorting.
 01568                properties.SortProperties();
 01569                propertyCache.StableSortByKey(static propInfo => propInfo.Order);
 01570            }
 1571
 4961572            OptionalPropertiesMask = requiredPropertiesMask?.Not();
 4961573            _propertyCache = propertyCache.ToArray();
 4961574            _propertyIndex = propertyIndex;
 1575
 1576            // Override global UnmappedMemberHandling configuration
 1577            // if type specifies an extension data property.
 4961578            EffectiveUnmappedMemberHandling = UnmappedMemberHandling ??
 4961579                (ExtensionDataProperty is null
 4961580                    ? Options.UnmappedMemberHandling
 4961581                    : JsonUnmappedMemberHandling.Skip);
 4961582        }
 1583
 1584        internal void PopulateParameterInfoValues(JsonParameterInfoValues[] parameterInfoValues)
 3331585        {
 3331586            Dictionary<ParameterLookupKey, JsonParameterInfoValues> parameterIndex = new(parameterInfoValues.Length);
 49951587            foreach (JsonParameterInfoValues parameterInfoValue in parameterInfoValues)
 19981588            {
 19981589                ParameterLookupKey paramKey = new(parameterInfoValue.ParameterType, parameterInfoValue.Name);
 19981590                parameterIndex.TryAdd(paramKey, parameterInfoValue); // Ignore conflicts since they are reported at seri
 19981591            }
 1592
 3331593            ParameterCount = parameterInfoValues.Length;
 3331594            _parameterInfoValuesIndex = parameterIndex;
 3331595        }
 1596
 1597        internal void ResolveMatchingParameterInfo(JsonPropertyInfo propertyInfo)
 29761598        {
 29761599            Debug.Assert(
 29761600                CreateObjectWithArgs is null || _parameterInfoValuesIndex is not null,
 29761601                "Metadata with parameterized constructors must have populated parameter info metadata.");
 1602
 29761603            if (_parameterInfoValuesIndex is not { } index)
 9781604            {
 9781605                return;
 1606            }
 1607
 19981608            string propertyName = propertyInfo.MemberName ?? propertyInfo.Name;
 19981609            ParameterLookupKey propKey = new(propertyInfo.PropertyType, propertyName);
 19981610            if (index.TryGetValue(propKey, out JsonParameterInfoValues? matchingParameterInfoValues))
 19981611            {
 19981612                propertyInfo.AddJsonParameterInfo(matchingParameterInfoValues);
 19981613            }
 29761614        }
 1615
 1616        internal void ConfigureConstructorParameters()
 3331617        {
 3331618            Debug.Assert(Kind == JsonTypeInfoKind.Object);
 3331619            Debug.Assert(DetermineUsesParameterizedConstructor());
 3331620            Debug.Assert(_propertyCache is not null);
 3331621            Debug.Assert(_parameterCache is null);
 1622
 3331623            List<JsonParameterInfo> parameterCache = new(ParameterCount);
 3331624            Dictionary<ParameterLookupKey, JsonParameterInfo> parameterIndex = new(ParameterCount);
 1625
 49951626            foreach (JsonPropertyInfo propertyInfo in _propertyCache)
 19981627            {
 19981628                JsonParameterInfo? parameterInfo = propertyInfo.AssociatedParameter;
 19981629                if (parameterInfo is null)
 01630                {
 01631                    continue;
 1632                }
 1633
 19981634                string propertyName = propertyInfo.MemberName ?? propertyInfo.Name;
 19981635                ParameterLookupKey paramKey = new(propertyInfo.PropertyType, propertyName);
 19981636                if (!parameterIndex.TryAdd(paramKey, parameterInfo))
 01637                {
 1638                    // Multiple object properties cannot bind to the same constructor parameter.
 01639                    ThrowHelper.ThrowInvalidOperationException_MultiplePropertiesBindToConstructorParameters(
 01640                        Type,
 01641                        parameterInfo.Name,
 01642                        propertyInfo.Name,
 01643                        parameterIndex[paramKey].MatchingProperty.Name);
 1644                }
 1645
 19981646                parameterCache.Add(parameterInfo);
 19981647            }
 1648
 3331649            if (ExtensionDataProperty is { AssociatedParameter: not null })
 01650            {
 01651                Debug.Assert(ExtensionDataProperty.MemberName is not null, "Custom property info cannot be data extensio
 01652                ThrowHelper.ThrowInvalidOperationException_ExtensionDataCannotBindToCtorParam(ExtensionDataProperty.Memb
 1653            }
 1654
 3331655            _parameterCache = parameterCache.ToArray();
 3331656            _parameterInfoValuesIndex = null;
 3331657        }
 1658
 1659        internal static void ValidateType(Type type)
 68851660        {
 68851661            if (IsInvalidForSerialization(type))
 01662            {
 01663                ThrowHelper.ThrowInvalidOperationException_CannotSerializeInvalidType(type, declaringType: null, memberI
 1664            }
 68851665        }
 1666
 1667        internal static bool IsInvalidForSerialization(Type type)
 98611668        {
 98611669            return type == typeof(void) || type.IsPointer || type.IsByRef || IsByRefLike(type) || type.ContainsGenericPa
 98611670        }
 1671
 1672        internal void MapInterfaceTypesToCallbacks()
 41471673        {
 41471674            Debug.Assert(!IsReadOnly);
 1675
 41471676            if (Kind is JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary)
 9651677            {
 9651678                if (typeof(IJsonOnSerializing).IsAssignableFrom(Type))
 01679                {
 01680                    OnSerializing = static obj => ((IJsonOnSerializing)obj).OnSerializing();
 01681                }
 1682
 9651683                if (typeof(IJsonOnSerialized).IsAssignableFrom(Type))
 01684                {
 01685                    OnSerialized = static obj => ((IJsonOnSerialized)obj).OnSerialized();
 01686                }
 1687
 9651688                if (typeof(IJsonOnDeserializing).IsAssignableFrom(Type))
 01689                {
 01690                    OnDeserializing = static obj => ((IJsonOnDeserializing)obj).OnDeserializing();
 01691                }
 1692
 9651693                if (typeof(IJsonOnDeserialized).IsAssignableFrom(Type))
 01694                {
 01695                    OnDeserialized = static obj => ((IJsonOnDeserialized)obj).OnDeserialized();
 01696                }
 9651697            }
 41471698        }
 1699
 1700        internal void SetCreateObjectIfCompatible(Delegate? createObject)
 41471701        {
 41471702            Debug.Assert(!IsReadOnly);
 1703
 1704            // Guard against the reflection resolver/source generator attempting to pass
 1705            // a CreateObject delegate to converters/metadata that do not support it.
 41471706            if (Converter.SupportsCreateObjectDelegate && !Converter.ConstructorIsParameterized)
 6321707            {
 6321708                SetCreateObject(createObject);
 6321709            }
 41471710        }
 1711
 1712        private static bool IsByRefLike(Type type)
 98611713        {
 1714#if NET
 98611715            return type.IsByRefLike;
 1716#else
 1717            if (!type.IsValueType)
 1718            {
 1719                return false;
 1720            }
 1721
 1722            object[] attributes = type.GetCustomAttributes(inherit: false);
 1723
 1724            for (int i = 0; i < attributes.Length; i++)
 1725            {
 1726                if (attributes[i].GetType().FullName == "System.Runtime.CompilerServices.IsByRefLikeAttribute")
 1727                {
 1728                    return true;
 1729                }
 1730            }
 1731
 1732            return false;
 1733#endif
 98611734        }
 1735
 1736        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 1737        internal bool SupportsPolymorphicDeserialization
 1738        {
 1739            get
 01740            {
 01741                Debug.Assert(IsConfigurationStarted);
 01742                return PolymorphicTypeResolver?.UsesTypeDiscriminators == true;
 01743            }
 1744        }
 1745
 1746        internal static bool IsValidExtensionDataProperty(Type propertyType)
 01747        {
 01748            return typeof(IDictionary<string, object>).IsAssignableFrom(propertyType) ||
 01749                typeof(IDictionary<string, JsonElement>).IsAssignableFrom(propertyType) ||
 01750                propertyType == typeof(IReadOnlyDictionary<string, object>) ||
 01751                propertyType == typeof(IReadOnlyDictionary<string, JsonElement>) ||
 01752                // Avoid a reference to typeof(JsonNode) to support trimming.
 01753                (propertyType.FullName == JsonObjectTypeName && ReferenceEquals(propertyType.Assembly, typeof(JsonTypeIn
 01754        }
 1755
 1756        private static JsonTypeInfoKind GetTypeInfoKind(Type type, JsonConverter converter)
 41471757        {
 41471758            if (type == typeof(object) && converter.CanBePolymorphic)
 861759            {
 1760                // System.Object is polymorphic and will not respect Properties
 861761                Debug.Assert(converter is ObjectConverter);
 861762                return JsonTypeInfoKind.None;
 1763            }
 1764
 40611765            switch (converter.ConverterStrategy)
 1766            {
 30961767                case ConverterStrategy.Value: return JsonTypeInfoKind.None;
 4961768                case ConverterStrategy.Object: return JsonTypeInfoKind.Object;
 1769                case ConverterStrategy.Union:
 1770                    // Nullable<TUnion> delegates to the underlying union converter, but the
 1771                    // nullable wrapper does not own union case metadata.
 01772                    return Nullable.GetUnderlyingType(type) is null ? JsonTypeInfoKind.Union : JsonTypeInfoKind.None;
 1981773                case ConverterStrategy.Enumerable: return JsonTypeInfoKind.Enumerable;
 2711774                case ConverterStrategy.Dictionary: return JsonTypeInfoKind.Dictionary;
 1775                case ConverterStrategy.None:
 01776                    Debug.Assert(converter is JsonConverterFactory);
 01777                    ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(type);
 1778                    return default;
 1779                default:
 01780                    Debug.Fail($"Unexpected class type: {converter.ConverterStrategy}");
 1781                    throw new InvalidOperationException();
 1782            }
 41471783        }
 1784
 1785        internal sealed class JsonPropertyInfoList : ConfigurationList<JsonPropertyInfo>
 1786        {
 1787            private readonly JsonTypeInfo _jsonTypeInfo;
 1788
 4961789            public JsonPropertyInfoList(JsonTypeInfo jsonTypeInfo)
 4961790            {
 4961791                _jsonTypeInfo = jsonTypeInfo;
 4961792            }
 1793
 01794            public override bool IsReadOnly => _jsonTypeInfo._properties == this && _jsonTypeInfo.IsReadOnly || _jsonTyp
 1795            protected override void OnCollectionModifying()
 29761796            {
 29761797                if (_jsonTypeInfo._properties == this)
 29761798                {
 29761799                    _jsonTypeInfo.VerifyMutable();
 29761800                }
 1801
 29761802                if (_jsonTypeInfo.Kind != JsonTypeInfoKind.Object)
 01803                {
 01804                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(_jsonTypeInfo.Kin
 1805                }
 29761806            }
 1807
 1808            protected override void ValidateAddedValue(JsonPropertyInfo item)
 29761809            {
 29761810                item.EnsureChildOf(_jsonTypeInfo);
 29761811            }
 1812
 1813            public void SortProperties()
 01814            {
 01815                _list.StableSortByKey(static propInfo => propInfo.Order);
 01816            }
 1817
 1818            /// <summary>
 1819            /// Used by the built-in resolvers to add property metadata applying conflict resolution.
 1820            /// </summary>
 1821            public void AddPropertyWithConflictResolution(JsonPropertyInfo jsonPropertyInfo, ref PropertyHierarchyResolu
 29761822            {
 29761823                Debug.Assert(!_jsonTypeInfo.IsConfigured);
 29761824                Debug.Assert(jsonPropertyInfo.MemberName is not null, "MemberName can be null in custom JsonPropertyInfo
 1825
 1826                // Algorithm should be kept in sync with the Roslyn equivalent in JsonSourceGenerator.Parser.cs
 29761827                string memberName = jsonPropertyInfo.MemberName;
 1828
 29761829                if (state.AddedProperties.TryAdd(jsonPropertyInfo.Name, (jsonPropertyInfo, Count)))
 29761830                {
 29761831                    Add(jsonPropertyInfo);
 29761832                    state.IsPropertyOrderSpecified |= jsonPropertyInfo.Order != 0;
 29761833                }
 1834                else
 01835                {
 1836                    // The JsonPropertyNameAttribute or naming policy resulted in a collision.
 01837                    (JsonPropertyInfo other, int index) = state.AddedProperties[jsonPropertyInfo.Name];
 1838
 01839                    if (other.IsIgnored)
 01840                    {
 1841                        // Overwrite previously cached property since it has [JsonIgnore].
 01842                        state.AddedProperties[jsonPropertyInfo.Name] = (jsonPropertyInfo, index);
 01843                        this[index] = jsonPropertyInfo;
 01844                        state.IsPropertyOrderSpecified |= jsonPropertyInfo.Order != 0;
 01845                    }
 1846                    else
 01847                    {
 01848                        bool ignoreCurrentProperty =
 01849                            // Does the current property have `JsonIgnoreAttribute`?
 01850                            jsonPropertyInfo.IsIgnored ||
 01851                            // Is the current property hidden by the previously cached property
 01852                            // (with `new` keyword, or by overriding)?
 01853                            jsonPropertyInfo.IsOverriddenOrShadowedBy(other) ||
 01854                            // Was a property with the same CLR name ignored? That property hid the current property,
 01855                            // thus, if it was ignored, the current property should be ignored too.
 01856                            (state.IgnoredProperties?.TryGetValue(memberName, out JsonPropertyInfo? ignored) == true && 
 1857
 01858                        if (!ignoreCurrentProperty)
 01859                        {
 01860                            ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(_jsonTypeInfo.Type
 1861                        }
 01862                    }
 01863                }
 1864
 29761865                if (jsonPropertyInfo.IsIgnored)
 01866                {
 01867                    (state.IgnoredProperties ??= new())[memberName] = jsonPropertyInfo;
 01868                }
 29761869            }
 1870        }
 1871
 1872        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 01873        private string DebuggerDisplay => $"Type = {Type.Name}, Kind = {Kind}";
 1874    }
 1875}
 1876

Methods/Properties

ParameterCount()
ParameterCache()
UsesParameterizedConstructor()
PropertyCache()
PropertyIndex()
.ctor(System.Type,System.Text.Json.Serialization.JsonConverter,System.Text.Json.JsonSerializerOptions)
GetProperty(System.ReadOnlySpan`1<System.Byte>,System.Text.Json.ReadStackFrame&,System.Byte[]&)
UpdateUtf8PropertyCache(System.Text.Json.ReadStackFrame&)
OptionalPropertiesMask()
ShouldTrackRequiredProperties()
.ctor(System.Type,System.Text.Json.Serialization.JsonConverter,System.Text.Json.JsonSerializerOptions)
ElementType()
KeyType()
CreateObject()
CreateObject(System.Func`1<System.Object>)
CreateObjectForExtensionDataProperty()
OnSerializing()
OnSerializing(System.Action`1<System.Object>)
OnSerialized()
OnSerialized(System.Action`1<System.Object>)
OnDeserializing()
OnDeserializing(System.Action`1<System.Object>)
OnDeserialized()
OnDeserialized(System.Action`1<System.Object>)
Properties()
PropertyList()
tePropertyList()
SourceGenDelayedPropertyInitializer(System.Func`2<System.Text.Json.Serialization.JsonSerializerContext,System.Text.Json.Serialization.Metadata.JsonPropertyInfo[]>)
PolymorphismOptions()
PolymorphismOptions(System.Text.Json.Serialization.Metadata.JsonPolymorphismOptions)
SetPolymorphismOptions(System.Text.Json.Serialization.Metadata.JsonPolymorphismOptions)
IsReadOnly()
MakeReadOnly()
UnionCases()
UnionCaseList()
teUnionCaseList()
.ctor(System.Text.Json.Serialization.Metadata.JsonTypeInfo,System.Collections.Generic.IEnumerable`1<System.Text.Json.Serialization.Metadata.JsonUnionCaseInfo>)
IsReadOnly()
OnCollectionModifying()
TypeClassifier()
TypeClassifier(System.Text.Json.Serialization.JsonTypeClassifier)
UnionDeconstructor()
UnionDeconstructor(System.Func`2<System.Object,System.ValueTuple`2<System.Type,System.Object>>)
SetUnionDeconstructor(System.Delegate)
UnionConstructor()
UnionConstructor(System.Func`3<System.Type,System.Object,System.Object>)
SetUnionConstructor(System.Delegate)
UnionValueTypeMap()
UnionAmbiguousValueTypes()
UnionNullableCaseType()
TypeClassifierFactory()
TypeClassifierFactory(System.Text.Json.Serialization.JsonTypeClassifierFactory)
TypeClassifierResolutionPending(System.Boolean)
CreateObjectWithArgs()
AddMethodDelegate()
ExtensionDataProperty()
PolymorphicTypeResolver()
HasSerializeHandler()
CanUseSerializeHandler()
PropertyMetadataSerializationNotSupported()
IsNullable()
ValidateCanBeUsedForPropertyMetadataSerialization()
ElementTypeInfo()
ElementTypeInfo(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
KeyTypeInfo()
KeyTypeInfo(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
Options()
Type()
Converter()
Kind()
PropertyInfoForTypeInfo()
NumberHandling()
NumberHandling(System.Nullable`1<System.Text.Json.Serialization.JsonNumberHandling>)
EffectiveNumberHandling()
UnmappedMemberHandling()
UnmappedMemberHandling(System.Nullable`1<System.Text.Json.Serialization.JsonUnmappedMemberHandling>)
EffectiveUnmappedMemberHandling()
PreferredPropertyObjectCreationHandling()
PreferredPropertyObjectCreationHandling(System.Nullable`1<System.Text.Json.Serialization.JsonObjectCreationHandling>)
OriginatingResolver()
OriginatingResolver(System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver)
ConstructorAttributeProvider()
ConstructorAttributeProvider(System.Reflection.ICustomAttributeProvider)
VerifyMutable()
IsCustomized()
IsConfigured()
IsConfigurationStarted()
EnsureConfigured()
ConfigureSynchronized()
Configure()
ValidateUnionContract()
CacheUnionNullableCaseType()
ConfigureTypeClassifier()
BuildUnionValueTypeMap(System.Collections.Generic.IList`1<System.Text.Json.Serialization.Metadata.JsonUnionCaseInfo>,System.Text.Json.JsonSerializerOptions,System.Text.Json.Serialization.Metadata.JsonTypeInfo)
AddUnionValueTypes(System.Text.Json.Serialization.JsonValueType,System.Type,System.Collections.Generic.Dictionary`2<System.Text.Json.Serialization.JsonValueType,System.Type>,System.Text.Json.Serialization.JsonValueType&)
AncestorPolymorphicType()
DetermineIsCompatibleWithCurrentOptions()
IsCurrentNodeCompatible()
IsCompatibleWithCurrentOptions()
DetermineUsesParameterizedConstructor()
CreateJsonTypeInfo(System.Text.Json.JsonSerializerOptions)
CreateJsonTypeInfo(System.Type,System.Text.Json.JsonSerializerOptions)
CreateJsonTypeInfo(System.Type,System.Text.Json.Serialization.JsonConverter,System.Text.Json.JsonSerializerOptions)
CreateJsonPropertyInfo(System.Type,System.String)
CreatePropertyUsingReflection(System.Type,System.Type)
.ctor(System.Text.Json.JsonSerializerOptions)
Type()
Name()
GetHashCode()
Equals(System.Text.Json.Serialization.Metadata.JsonTypeInfo/ParameterLookupKey)
Equals(System.Object)
ConfigureProperties()
PopulateParameterInfoValues(System.Text.Json.Serialization.Metadata.JsonParameterInfoValues[])
ResolveMatchingParameterInfo(System.Text.Json.Serialization.Metadata.JsonPropertyInfo)
ConfigureConstructorParameters()
ValidateType(System.Type)
IsInvalidForSerialization(System.Type)
MapInterfaceTypesToCallbacks()
SetCreateObjectIfCompatible(System.Delegate)
IsByRefLike(System.Type)
SupportsPolymorphicDeserialization()
IsValidExtensionDataProperty(System.Type)
GetTypeInfoKind(System.Type,System.Text.Json.Serialization.JsonConverter)
.ctor(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
IsReadOnly()
OnCollectionModifying()
ValidateAddedValue(System.Text.Json.Serialization.Metadata.JsonPropertyInfo)
SortProperties()
AddPropertyWithConflictResolution(System.Text.Json.Serialization.Metadata.JsonPropertyInfo,System.Text.Json.Serialization.Metadata.JsonTypeInfo/PropertyHierarchyResolutionState&)
DebuggerDisplay()