< Summary

Line coverage
42%
Covered lines: 350
Uncovered lines: 475
Coverable lines: 825
Total lines: 1954
Line coverage: 42.4%
Branch coverage
38%
Covered branches: 113
Total branches: 296
Branch coverage: 38.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
File 1: GetTypeInfo(...)0%220%
File 1: TryGetTypeInfo(...)0%220%
File 1: GetTypeInfo()100%110%
File 1: TryGetTypeInfo(...)100%110%
File 1: GetTypeInfoInternal(...)60%202071.42%
File 1: TryGetTypeInfoCached(...)50%2257.14%
File 1: GetTypeInfoForRootType(...)100%44100%
File 1: TryGetPolymorphicTypeInfoForRootType(...)0%440%
File 1: ClearCaches()0%220%
File 1: .ctor(...)100%11100%
File 1: GetOrAddTypeInfo(...)50%44100%
File 1: TryGetTypeInfo(...)100%22100%
File 1: Clear()100%110%
File 1: GetOrAddCacheEntry(...)100%11100%
File 1: CreateCacheEntry(...)100%1155.55%
File 1: FallBackToNearestAncestor(...)0%440%
File 1: DetermineNearestAncestor(...)0%16160%
File 1: .ctor(...)100%11100%
File 1: .ctor(...)100%110%
File 1: GetResult()50%22100%
File 1: .cctor()100%11100%
File 1: GetOrCreate(...)80%101086.66%
File 1: TryGetContext(...)100%1212100%
File 1: Equals(...)50%5656100%
File 1: CompareLists(System.Text.Json.Serialization.ConfigurationList`1<TValue>,System.Text.Json.Serialization.ConfigurationList`1<TValue>)16.66%121225%
File 1: GetHashCode(...)100%11100%
File 1: AddListHashCode(System.HashCode&,System.Text.Json.Serialization.ConfigurationList`1<TValue>)50%4444.44%
File 1: AddHashCode(System.HashCode&,TValue)100%22100%
File 2: GetConverter(...)0%440%
File 2: GetConverterInternal(...)100%110%
File 2: GetConverterFromList(...)16.66%6633.33%
File 2: ExpandConverterFactory(...)100%22100%
File 2: CheckConverterNullabilityIsSameAsPropertyType(...)83.33%6666.66%
File 3: .ctor()100%11100%
File 3: .ctor(...)0%220%
File 3: .ctor(...)0%660%
File 3: TrackOptionsInstance(...)100%11100%
File 3: .cctor()100%11100%
File 3: AddContext()100%110%
File 3: MakeReadOnly()50%2266.66%
File 3: MakeReadOnly(...)75%4476.92%
File 3: ConfigureForJsonSerializer()30%202042.85%
File 3: GetTypeInfoNoCaching(...)50%121244%
File 3: GetDocumentOptions()100%110%
File 3: GetNodeOptions()100%11100%
File 3: GetReaderOptions()100%11100%
File 3: GetWriterOptions()100%110%
File 3: VerifyMutable()50%2260%
File 3: .ctor(...)100%110%
File 3: OnCollectionModifying()100%110%
File 3: .ctor(...)100%110%
File 3: DetachFromOptions()100%110%
File 3: ValidateAddedValue(...)0%660%
File 3: OnCollectionModifying()0%220%
File 3: OnCollectionModified()0%220%
File 3: GetOrCreateSingleton(...)0%440%

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializerOptions.Caching.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.Concurrent;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Runtime.CompilerServices;
 9using System.Runtime.ExceptionServices;
 10using System.Text.Json.Serialization;
 11using System.Text.Json.Serialization.Metadata;
 12using System.Threading;
 13
 14namespace System.Text.Json
 15{
 16    public sealed partial class JsonSerializerOptions
 17    {
 18        /// <summary>
 19        /// Encapsulates all cached metadata referenced by the current <see cref="JsonSerializerOptions" /> instance.
 20        /// Context can be shared across multiple equivalent options instances.
 21        /// </summary>
 22        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 23        internal CachingContext CacheContext
 24        {
 25            get
 6732926            {
 6732927                Debug.Assert(IsReadOnly);
 6732928                return _cachingContext ?? GetOrCreate();
 29
 30                CachingContext GetOrCreate()
 68231                {
 68232                    CachingContext ctx = TrackedCachingContexts.GetOrCreate(this);
 68233                    return Interlocked.CompareExchange(ref _cachingContext, ctx, null) ?? ctx;
 68234                }
 6732935            }
 36        }
 37
 38        private CachingContext? _cachingContext;
 39
 40        // Simple LRU cache for the public (de)serialize entry points that avoid some lookups in _cachingContext.
 41        private volatile JsonTypeInfo? _lastTypeInfo;
 42
 43        /// <summary>
 44        /// Gets the <see cref="JsonTypeInfo"/> contract metadata resolved by the current <see cref="JsonSerializerOptio
 45        /// </summary>
 46        /// <param name="type">The type to resolve contract metadata for.</param>
 47        /// <returns>The contract metadata resolved for <paramref name="type"/>.</returns>
 48        /// <exception cref="ArgumentNullException"><paramref name="type"/> is <see langword="null"/>.</exception>
 49        /// <exception cref="ArgumentException"><paramref name="type"/> is not valid for serialization.</exception>
 50        /// <remarks>
 51        /// Returned metadata can be downcast to <see cref="JsonTypeInfo{T}"/> and used with the relevant <see cref="Jso
 52        ///
 53        /// If the <see cref="JsonSerializerOptions"/> instance is locked for modification, the method will return a cac
 54        /// </remarks>
 55        public JsonTypeInfo GetTypeInfo(Type type)
 056        {
 057            ArgumentNullException.ThrowIfNull(type);
 58
 059            if (JsonTypeInfo.IsInvalidForSerialization(type))
 060            {
 061                ThrowHelper.ThrowArgumentException_CannotSerializeInvalidType(nameof(type), type, null, null);
 62            }
 63
 064            return GetTypeInfoInternal(type, resolveIfMutable: true);
 065        }
 66
 67        /// <summary>
 68        /// Tries to get the <see cref="JsonTypeInfo"/> contract metadata resolved by the current <see cref="JsonSeriali
 69        /// </summary>
 70        /// <param name="type">The type to resolve contract metadata for.</param>
 71        /// <param name="typeInfo">The resolved contract metadata, or <see langword="null" /> if not contract could be r
 72        /// <returns><see langword="true"/> if a contract for <paramref name="type"/> was found, or <see langword="false
 73        /// <exception cref="ArgumentNullException"><paramref name="type"/> is <see langword="null"/>.</exception>
 74        /// <exception cref="ArgumentException"><paramref name="type"/> is not valid for serialization.</exception>
 75        /// <remarks>
 76        /// Returned metadata can be downcast to <see cref="JsonTypeInfo{T}"/> and used with the relevant <see cref="Jso
 77        ///
 78        /// If the <see cref="JsonSerializerOptions"/> instance is locked for modification, the method will return a cac
 79        /// </remarks>
 80        public bool TryGetTypeInfo(Type type, [NotNullWhen(true)] out JsonTypeInfo? typeInfo)
 081        {
 082            ArgumentNullException.ThrowIfNull(type);
 83
 084            if (JsonTypeInfo.IsInvalidForSerialization(type))
 085            {
 086                ThrowHelper.ThrowArgumentException_CannotSerializeInvalidType(nameof(type), type, null, null);
 87            }
 88
 089            typeInfo = GetTypeInfoInternal(type, ensureNotNull: null, resolveIfMutable: true);
 090            return typeInfo is not null;
 091        }
 92
 93        /// <summary>
 94        /// Gets the <see cref="JsonTypeInfo{T}"/> contract metadata resolved by the current <see cref="JsonSerializerOp
 95        /// </summary>
 96        /// <typeparam name="T">The type to resolve contract metadata for.</typeparam>
 97        /// <returns>The contract metadata resolved for <typeparamref name="T"/>.</returns>
 98        /// <exception cref="ArgumentException"><typeparamref name="T"/> is not valid for serialization.</exception>
 99        /// <remarks>
 100        /// If the <see cref="JsonSerializerOptions"/> instance is locked for modification, the method will return a cac
 101        /// </remarks>
 102        public JsonTypeInfo<T> GetTypeInfo<T>()
 0103        {
 0104            return (JsonTypeInfo<T>)GetTypeInfo(typeof(T));
 0105        }
 106
 107        /// <summary>
 108        /// Tries to get the <see cref="JsonTypeInfo{T}"/> contract metadata resolved by the current <see cref="JsonSeri
 109        /// </summary>
 110        /// <typeparam name="T">The type to resolve contract metadata for.</typeparam>
 111        /// <param name="typeInfo">The resolved contract metadata, or <see langword="null" /> if no contract could be re
 112        /// <returns><see langword="true"/> if a contract for <typeparamref name="T"/> was found, or <see langword="fals
 113        /// <exception cref="ArgumentException"><typeparamref name="T"/> is not valid for serialization.</exception>
 114        /// <remarks>
 115        /// If the <see cref="JsonSerializerOptions"/> instance is locked for modification, the method will return a cac
 116        /// </remarks>
 117        public bool TryGetTypeInfo<T>([NotNullWhen(true)] out JsonTypeInfo<T>? typeInfo)
 0118        {
 0119            bool success = TryGetTypeInfo(typeof(T), out JsonTypeInfo? nonGeneric);
 0120            typeInfo = (JsonTypeInfo<T>?)nonGeneric;
 0121            return success;
 0122        }
 123
 124        /// <summary>
 125        /// Same as GetTypeInfo but without validation and additional knobs.
 126        /// </summary>
 127        [return: NotNullIfNotNull(nameof(ensureNotNull))]
 128        internal JsonTypeInfo? GetTypeInfoInternal(
 129            Type type,
 130            bool ensureConfigured = true,
 131            // We can't assert non-nullability on the basis of boolean parameters,
 132            // so use a nullable representation instead to piggy-back on the NotNullIfNotNull attribute.
 133            bool? ensureNotNull = true,
 134            bool resolveIfMutable = false,
 135            bool fallBackToNearestAncestorType = false)
 30567136        {
 30567137            Debug.Assert(!fallBackToNearestAncestorType || IsReadOnly, "ancestor resolution should only be invoked in re
 30567138            Debug.Assert(ensureNotNull is null or true, "Explicitly passing false will result in invalid result annotati
 139
 30567140            JsonTypeInfo? typeInfo = null;
 141
 30567142            if (IsReadOnly)
 30567143            {
 30567144                typeInfo = CacheContext.GetOrAddTypeInfo(type, fallBackToNearestAncestorType);
 30567145                if (ensureConfigured)
 30567146                {
 30567147                    typeInfo?.EnsureConfigured();
 30567148                }
 30567149            }
 0150            else if (resolveIfMutable)
 0151            {
 0152                typeInfo = GetTypeInfoNoCaching(type);
 0153            }
 154
 30567155            if (typeInfo is null && ensureNotNull is true)
 0156            {
 0157                ThrowHelper.ThrowNotSupportedException_NoMetadataForType(type, TypeInfoResolver);
 158            }
 159
 30567160            return typeInfo;
 30567161        }
 162
 163        internal bool TryGetTypeInfoCached(Type type, [NotNullWhen(true)] out JsonTypeInfo? typeInfo)
 7794164        {
 7794165            if (_cachingContext == null)
 0166            {
 0167                typeInfo = null;
 0168                return false;
 169            }
 170
 7794171            return _cachingContext.TryGetTypeInfo(type, out typeInfo);
 7794172        }
 173
 174        /// <summary>
 175        /// Return the TypeInfo for root API calls.
 176        /// This has an LRU cache that is intended only for public API calls that specify the root type.
 177        /// </summary>
 178        internal JsonTypeInfo GetTypeInfoForRootType(Type type, bool fallBackToNearestAncestorType = false)
 54560179        {
 54560180            JsonTypeInfo? jsonTypeInfo = _lastTypeInfo;
 181
 54560182            if (jsonTypeInfo?.Type != type)
 27162183            {
 27162184                _lastTypeInfo = jsonTypeInfo = GetTypeInfoInternal(type, fallBackToNearestAncestorType: fallBackToNeares
 27162185            }
 186
 54560187            return jsonTypeInfo;
 54560188        }
 189
 190        internal bool TryGetPolymorphicTypeInfoForRootType(object rootValue, [NotNullWhen(true)] out JsonTypeInfo? polym
 0191        {
 0192            Debug.Assert(rootValue != null);
 193
 0194            Type runtimeType = rootValue.GetType();
 0195            if (runtimeType != JsonTypeInfo.ObjectType)
 0196            {
 197                // To determine the contract for an object value:
 198                // 1. Find the JsonTypeInfo for the runtime type with fallback to the nearest ancestor, if not available
 199                // 2. If the resolved type is deriving from a polymorphic type, use the contract of the polymorphic type
 0200                polymorphicTypeInfo = GetTypeInfoForRootType(runtimeType, fallBackToNearestAncestorType: true);
 0201                if (polymorphicTypeInfo.AncestorPolymorphicType is { } ancestorPolymorphicType)
 0202                {
 0203                    polymorphicTypeInfo = ancestorPolymorphicType;
 0204                }
 0205                return true;
 206            }
 207
 0208            polymorphicTypeInfo = null;
 0209            return false;
 0210        }
 211
 212        // Caches the resolved JsonTypeInfo<object> for faster access during root-level object type serialization.
 213        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 214        internal JsonTypeInfo ObjectTypeInfo
 215        {
 216            get
 1364217            {
 1364218                Debug.Assert(IsReadOnly);
 1364219                return _objectTypeInfo ??= GetTypeInfoInternal(JsonTypeInfo.ObjectType);
 1364220            }
 221        }
 222
 223        private JsonTypeInfo? _objectTypeInfo;
 224
 225        internal void ClearCaches()
 0226        {
 0227            _cachingContext?.Clear();
 0228            _lastTypeInfo = null;
 0229            _objectTypeInfo = null;
 0230        }
 231
 232        /// <summary>
 233        /// Stores and manages all reflection caches for one or more <see cref="JsonSerializerOptions"/> instances.
 234        /// NB the type encapsulates the original options instance and only consults that one when building new types;
 235        /// this is to prevent multiple options instances from leaking into the object graphs of converters which
 236        /// could break user invariants.
 237        /// </summary>
 238        internal sealed class CachingContext
 239        {
 269240            private readonly ConcurrentDictionary<Type, CacheEntry> _cache = new();
 241#if !NET
 242            private readonly Func<Type, CacheEntry> _cacheEntryFactory;
 243#endif
 244
 269245            public CachingContext(JsonSerializerOptions options, int hashCode)
 269246            {
 269247                Options = options;
 269248                HashCode = hashCode;
 249#if !NET
 250                _cacheEntryFactory = type => CreateCacheEntry(type, this);
 251#endif
 269252            }
 253
 12667254            public JsonSerializerOptions Options { get; }
 4936255            public int HashCode { get; }
 256            // Property only accessed by reflection in testing -- do not remove.
 257            // If changing please ensure that src/ILLink.Descriptors.LibraryBuild.xml is up-to-date.
 0258            public int Count => _cache.Count;
 259
 260            public JsonTypeInfo? GetOrAddTypeInfo(Type type, bool fallBackToNearestAncestorType = false)
 30567261            {
 30567262                CacheEntry entry = GetOrAddCacheEntry(type);
 30567263                return fallBackToNearestAncestorType && !entry.HasResult
 30567264                    ? FallBackToNearestAncestor(type, entry)
 30567265                    : entry.GetResult();
 30567266            }
 267
 268            public bool TryGetTypeInfo(Type type, [NotNullWhen(true)] out JsonTypeInfo? typeInfo)
 7794269            {
 7794270                _cache.TryGetValue(type, out CacheEntry? entry);
 7794271                typeInfo = entry?.TypeInfo;
 7794272                return typeInfo is not null;
 7794273            }
 274
 275            public void Clear()
 0276            {
 0277                _cache.Clear();
 0278            }
 279
 280            private CacheEntry GetOrAddCacheEntry(Type type)
 30567281            {
 282#if NET
 30567283                return _cache.GetOrAdd(type, CreateCacheEntry, this);
 284#else
 285                return _cache.GetOrAdd(type, _cacheEntryFactory);
 286#endif
 30567287            }
 288
 289            private static CacheEntry CreateCacheEntry(Type type, CachingContext context)
 12254290            {
 291                try
 12254292                {
 12254293                    JsonTypeInfo? typeInfo = context.Options.GetTypeInfoNoCaching(type);
 12254294                    return new CacheEntry(typeInfo);
 295                }
 0296                catch (Exception ex)
 0297                {
 0298                    ExceptionDispatchInfo edi = ExceptionDispatchInfo.Capture(ex);
 0299                    return new CacheEntry(edi);
 300                }
 12254301            }
 302
 303            private JsonTypeInfo? FallBackToNearestAncestor(Type type, CacheEntry entry)
 0304            {
 0305                Debug.Assert(!entry.HasResult);
 306
 0307                CacheEntry? nearestAncestor = entry.IsNearestAncestorResolved
 0308                    ? entry.NearestAncestor
 0309                    : DetermineNearestAncestor(type, entry);
 310
 0311                return nearestAncestor?.GetResult();
 0312            }
 313
 314            [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
 315                Justification = "We only need to examine the interface types that are supported by the underlying resolv
 316            private CacheEntry? DetermineNearestAncestor(Type type, CacheEntry entry)
 0317            {
 318                // In cases where the underlying TypeInfoResolver returns `null` for a given type,
 319                // this method traverses the hierarchy above the type to determine potential
 320                // ancestors for which the resolver does provide metadata. This can be useful in
 321                // cases where we're using a source generator and are trying to serialize private
 322                // implementations of an interface that is supported by the source generator.
 323                // NB this algorithm runs lazily and unsynchronized *after* the CacheEntry has been looked up
 324                // from the global cache, so care should be taken to avoid potential race conditions.
 325                //
 326                // IMPORTANT: nearest-ancestor resolution should be reserved for weakly-typed serialization.
 327                // Attempting to use it in strongly typed operations or deserialization will invariably
 328                // result in an invalid cast exception, so use with caution.
 329
 0330                Debug.Assert(!entry.HasResult);
 0331                CacheEntry? candidate = null;
 0332                Type? candidateType = null;
 333
 0334                for (Type? current = type.BaseType; current != null; current = current.BaseType)
 0335                {
 0336                    if (current == JsonTypeInfo.ObjectType)
 0337                    {
 338                        // Avoid falling back to the contract for object since it's polymorphic
 339                        // and it would try to send us back to the runtime type that isn't supported.
 0340                        break;
 341                    }
 342
 0343                    candidate = GetOrAddCacheEntry(current);
 0344                    if (candidate.HasResult)
 0345                    {
 346                        // We found a type in the class hierarchy that has a contract -- stop looking further up.
 0347                        candidateType = current;
 0348                        break;
 349                    }
 0350                }
 351
 0352                foreach (Type interfaceType in type.GetInterfaces())
 0353                {
 0354                    CacheEntry interfaceEntry = GetOrAddCacheEntry(interfaceType);
 0355                    if (interfaceEntry.HasResult)
 0356                    {
 0357                        if (candidateType != null)
 0358                        {
 0359                            if (interfaceType.IsAssignableFrom(candidateType))
 0360                            {
 361                                // The previous candidate is more derived than the
 362                                // current interface -- keep our previous choice.
 0363                                continue;
 364                            }
 0365                            else if (candidateType.IsAssignableFrom(interfaceType))
 0366                            {
 367                                // The current interface is more derived than the
 368                                // previous candidate -- replace the candidate value.
 0369                            }
 370                            else
 0371                            {
 372                                // We have found two possible ancestors that are not in subtype relationship.
 373                                // This indicates we have encountered a diamond ambiguity -- abort search and record an 
 0374                                NotSupportedException nse = ThrowHelper.GetNotSupportedException_AmbiguousMetadataForTyp
 0375                                candidate = new CacheEntry(ExceptionDispatchInfo.Capture(nse));
 0376                                break;
 377                            }
 0378                        }
 379
 0380                        candidate = interfaceEntry;
 0381                        candidateType = interfaceType;
 0382                    }
 0383                }
 384
 0385                entry.NearestAncestor = candidate;
 0386                entry.IsNearestAncestorResolved = true;
 0387                return candidate;
 0388            }
 389
 390            private sealed class CacheEntry
 391            {
 392                public readonly bool HasResult;
 393                public readonly JsonTypeInfo? TypeInfo;
 394                public readonly ExceptionDispatchInfo? ExceptionDispatchInfo;
 395
 396                public volatile bool IsNearestAncestorResolved;
 397                public CacheEntry? NearestAncestor;
 398
 12254399                public CacheEntry(JsonTypeInfo? typeInfo)
 12254400                {
 12254401                    TypeInfo = typeInfo;
 12254402                    HasResult = typeInfo is not null;
 12254403                }
 404
 0405                public CacheEntry(ExceptionDispatchInfo exception)
 0406                {
 0407                    ExceptionDispatchInfo = exception;
 0408                    HasResult = true;
 0409                }
 410
 411                public JsonTypeInfo? GetResult()
 30567412                {
 30567413                    ExceptionDispatchInfo?.Throw();
 30567414                    return TypeInfo;
 30567415                }
 416            }
 417        }
 418
 419        /// <summary>
 420        /// Defines a cache of CachingContexts; instead of using a ConditionalWeakTable which can be slow to traverse
 421        /// this approach uses a fixed-size array of weak references of <see cref="CachingContext"/> that can be looked 
 422        /// Relevant caching contexts are looked up by linear traversal using the equality comparison defined by <see cr
 423        /// </summary>
 424        internal static class TrackedCachingContexts
 425        {
 426            private const int MaxTrackedContexts = 64;
 1427            private static readonly WeakReference<CachingContext>?[] s_trackedContexts = new WeakReference<CachingContex
 1428            private static readonly EqualityComparer s_optionsComparer = new();
 429
 430            public static CachingContext GetOrCreate(JsonSerializerOptions options)
 682431            {
 682432                Debug.Assert(options.IsReadOnly, "Cannot create caching contexts for mutable JsonSerializerOptions insta
 682433                Debug.Assert(options._typeInfoResolver != null);
 434
 682435                int hashCode = s_optionsComparer.GetHashCode(options);
 436
 682437                if (TryGetContext(options, hashCode, out int firstUnpopulatedIndex, out CachingContext? result))
 413438                {
 413439                    return result;
 440                }
 269441                else if (firstUnpopulatedIndex < 0)
 0442                {
 443                    // Cache is full; return a fresh instance.
 0444                    return new CachingContext(options, hashCode);
 445                }
 446
 269447                lock (s_trackedContexts)
 269448                {
 269449                    if (TryGetContext(options, hashCode, out firstUnpopulatedIndex, out result))
 0450                    {
 0451                        return result;
 452                    }
 453
 269454                    var ctx = new CachingContext(options, hashCode);
 455
 269456                    if (firstUnpopulatedIndex >= 0)
 269457                    {
 458                        // Cache has capacity -- store the context in the first available index.
 269459                        ref WeakReference<CachingContext>? weakRef = ref s_trackedContexts[firstUnpopulatedIndex];
 460
 269461                        if (weakRef is null)
 14462                        {
 14463                            weakRef = new(ctx);
 14464                        }
 465                        else
 255466                        {
 255467                            Debug.Assert(!weakRef.TryGetTarget(out _));
 255468                            weakRef.SetTarget(ctx);
 255469                        }
 269470                    }
 471
 269472                    return ctx;
 473                }
 682474            }
 475
 476            private static bool TryGetContext(
 477                JsonSerializerOptions options,
 478                int hashCode,
 479                out int firstUnpopulatedIndex,
 480                [NotNullWhen(true)] out CachingContext? result)
 951481            {
 951482                WeakReference<CachingContext>?[] trackedContexts = s_trackedContexts;
 483
 951484                firstUnpopulatedIndex = -1;
 74290485                for (int i = 0; i < trackedContexts.Length; i++)
 36607486                {
 36607487                    WeakReference<CachingContext>? weakRef = trackedContexts[i];
 488
 36607489                    if (weakRef is null || !weakRef.TryGetTarget(out CachingContext? ctx))
 31671490                    {
 31671491                        if (firstUnpopulatedIndex < 0)
 679492                        {
 679493                            firstUnpopulatedIndex = i;
 679494                        }
 31671495                    }
 4936496                    else if (hashCode == ctx.HashCode && s_optionsComparer.Equals(options, ctx.Options))
 413497                    {
 413498                        result = ctx;
 413499                        return true;
 500                    }
 36194501                }
 502
 538503                result = null;
 538504                return false;
 951505            }
 506        }
 507
 508        /// <summary>
 509        /// Provides a conservative equality comparison for JsonSerializerOptions instances.
 510        /// If two instances are equivalent, they should generate identical metadata caches;
 511        /// the converse however does not necessarily hold.
 512        /// </summary>
 513        private sealed class EqualityComparer : IEqualityComparer<JsonSerializerOptions>
 514        {
 515            public bool Equals(JsonSerializerOptions? left, JsonSerializerOptions? right)
 413516            {
 413517                Debug.Assert(left != null && right != null);
 518
 413519                return
 413520                    left._dictionaryKeyPolicy == right._dictionaryKeyPolicy &&
 413521                    left._jsonPropertyNamingPolicy == right._jsonPropertyNamingPolicy &&
 413522                    left._readCommentHandling == right._readCommentHandling &&
 413523                    left._referenceHandler == right._referenceHandler &&
 413524                    left._encoder == right._encoder &&
 413525                    left._defaultIgnoreCondition == right._defaultIgnoreCondition &&
 413526                    left._numberHandling == right._numberHandling &&
 413527                    left._preferredObjectCreationHandling == right._preferredObjectCreationHandling &&
 413528                    left._unknownTypeHandling == right._unknownTypeHandling &&
 413529                    left._unmappedMemberHandling == right._unmappedMemberHandling &&
 413530                    left._defaultBufferSize == right._defaultBufferSize &&
 413531                    left._maxDepth == right._maxDepth &&
 413532                    left.NewLine == right.NewLine && // Read through property due to lazy initialization of the backing 
 413533                    left._allowOutOfOrderMetadataProperties == right._allowOutOfOrderMetadataProperties &&
 413534                    left._allowTrailingCommas == right._allowTrailingCommas &&
 413535                    left._respectNullableAnnotations == right._respectNullableAnnotations &&
 413536                    left._respectRequiredConstructorParameters == right._respectRequiredConstructorParameters &&
 413537                    left._ignoreNullValues == right._ignoreNullValues &&
 413538                    left._ignoreReadOnlyProperties == right._ignoreReadOnlyProperties &&
 413539                    left._ignoreReadonlyFields == right._ignoreReadonlyFields &&
 413540                    left._includeFields == right._includeFields &&
 413541                    left._propertyNameCaseInsensitive == right._propertyNameCaseInsensitive &&
 413542                    left._writeIndented == right._writeIndented &&
 413543                    left._indentCharacter == right._indentCharacter &&
 413544                    left._indentSize == right._indentSize &&
 413545                    left._typeInfoResolver == right._typeInfoResolver &&
 413546                    left._allowDuplicateProperties == right._allowDuplicateProperties &&
 413547                    CompareLists(left._converters, right._converters);
 548
 549                static bool CompareLists<TValue>(ConfigurationList<TValue>? left, ConfigurationList<TValue>? right)
 550                    where TValue : class?
 413551                {
 552                    // equates null with empty lists
 413553                    if (left is null)
 413554                        return right is null || right.Count == 0;
 555
 0556                    if (right is null)
 0557                        return left.Count == 0;
 558
 559                    int n;
 0560                    if ((n = left.Count) != right.Count)
 0561                    {
 0562                        return false;
 563                    }
 564
 0565                    for (int i = 0; i < n; i++)
 0566                    {
 0567                        if (left[i] != right[i])
 0568                        {
 0569                            return false;
 570                        }
 0571                    }
 572
 0573                    return true;
 413574                }
 413575            }
 576
 577            public int GetHashCode(JsonSerializerOptions options)
 682578            {
 682579                HashCode hc = default;
 580
 682581                AddHashCode(ref hc, options._dictionaryKeyPolicy);
 682582                AddHashCode(ref hc, options._jsonPropertyNamingPolicy);
 682583                AddHashCode(ref hc, options._readCommentHandling);
 682584                AddHashCode(ref hc, options._referenceHandler);
 682585                AddHashCode(ref hc, options._encoder);
 682586                AddHashCode(ref hc, options._defaultIgnoreCondition);
 682587                AddHashCode(ref hc, options._numberHandling);
 682588                AddHashCode(ref hc, options._preferredObjectCreationHandling);
 682589                AddHashCode(ref hc, options._unknownTypeHandling);
 682590                AddHashCode(ref hc, options._unmappedMemberHandling);
 682591                AddHashCode(ref hc, options._defaultBufferSize);
 682592                AddHashCode(ref hc, options._maxDepth);
 682593                AddHashCode(ref hc, options.NewLine); // Read through property due to lazy initialization of the backing
 682594                AddHashCode(ref hc, options._allowOutOfOrderMetadataProperties);
 682595                AddHashCode(ref hc, options._allowTrailingCommas);
 682596                AddHashCode(ref hc, options._respectNullableAnnotations);
 682597                AddHashCode(ref hc, options._respectRequiredConstructorParameters);
 682598                AddHashCode(ref hc, options._ignoreNullValues);
 682599                AddHashCode(ref hc, options._ignoreReadOnlyProperties);
 682600                AddHashCode(ref hc, options._ignoreReadonlyFields);
 682601                AddHashCode(ref hc, options._includeFields);
 682602                AddHashCode(ref hc, options._propertyNameCaseInsensitive);
 682603                AddHashCode(ref hc, options._writeIndented);
 682604                AddHashCode(ref hc, options._indentCharacter);
 682605                AddHashCode(ref hc, options._indentSize);
 682606                AddHashCode(ref hc, options._typeInfoResolver);
 682607                AddHashCode(ref hc, options._allowDuplicateProperties);
 682608                AddListHashCode(ref hc, options._converters);
 609
 682610                return hc.ToHashCode();
 611
 612                static void AddListHashCode<TValue>(ref HashCode hc, ConfigurationList<TValue>? list)
 682613                {
 614                    // equates null with empty lists
 682615                    if (list is null)
 682616                        return;
 617
 0618                    int n = list.Count;
 0619                    for (int i = 0; i < n; i++)
 0620                    {
 0621                        AddHashCode(ref hc, list[i]);
 0622                    }
 682623                }
 624
 625                static void AddHashCode<TValue>(ref HashCode hc, TValue? value)
 18414626                {
 18414627                    if (typeof(TValue).IsSealed)
 15004628                    {
 15004629                        hc.Add(value);
 15004630                    }
 631                    else
 3410632                    {
 633                        // Use the built-in hashcode for types that could be overriding GetHashCode().
 3410634                        hc.Add(RuntimeHelpers.GetHashCode(value));
 3410635                    }
 18414636                }
 682637            }
 638
 639#if !NET
 640            /// <summary>
 641            /// Polyfill for System.HashCode.
 642            /// </summary>
 643            private struct HashCode
 644            {
 645                private int _hashCode;
 646                public void Add<T>(T? value) => _hashCode = (_hashCode, value).GetHashCode();
 647                public int ToHashCode() => _hashCode;
 648            }
 649#endif
 650        }
 651    }
 652}

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializerOptions.Converters.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.CodeAnalysis;
 6using System.Text.Json.Reflection;
 7using System.Text.Json.Serialization;
 8using System.Text.Json.Serialization.Metadata;
 9
 10namespace System.Text.Json
 11{
 12    /// <summary>
 13    /// Provides options to be used with <see cref="JsonSerializer"/>.
 14    /// </summary>
 15    public sealed partial class JsonSerializerOptions
 16    {
 17        /// <summary>
 18        /// The list of custom converters.
 19        /// </summary>
 20        /// <remarks>
 21        /// Once serialization or deserialization occurs, the list cannot be modified.
 22        /// </remarks>
 023        public IList<JsonConverter> Converters => _converters ??= new(this);
 24
 25        /// <summary>
 26        /// Returns the converter for the specified type.
 27        /// </summary>
 28        /// <param name="typeToConvert">The type to return a converter for.</param>
 29        /// <returns>
 30        /// The converter for the given type.
 31        /// </returns>
 32        /// <exception cref="InvalidOperationException">
 33        /// The configured <see cref="JsonConverter"/> for <paramref name="typeToConvert"/> returned an invalid converte
 34        /// </exception>
 35        /// <exception cref="NotSupportedException">
 36        /// There is no compatible <see cref="System.Text.Json.Serialization.JsonConverter"/>
 37        /// for <paramref name="typeToConvert"/> or its serializable members.
 38        /// </exception>
 39        [RequiresUnreferencedCode("Getting a converter for a type may require reflection which depends on unreferenced c
 40        [RequiresDynamicCode("Getting a converter for a type may require reflection which depends on runtime code genera
 41        public JsonConverter GetConverter(Type typeToConvert)
 042        {
 043            ArgumentNullException.ThrowIfNull(typeToConvert);
 44
 045            if (JsonSerializer.IsReflectionEnabledByDefault)
 046            {
 47                // Backward compatibility -- root & query the default reflection converters
 48                // but do not populate the TypeInfoResolver setting.
 049                if (_typeInfoResolver is null)
 050                {
 051                    return DefaultJsonTypeInfoResolver.GetConverterForType(typeToConvert, this);
 52                }
 053            }
 54
 055            return GetConverterInternal(typeToConvert);
 056        }
 57
 58        /// <summary>
 59        /// Same as GetConverter but without defaulting to reflection converters.
 60        /// </summary>
 61        internal JsonConverter GetConverterInternal(Type typeToConvert)
 062        {
 063            JsonTypeInfo jsonTypeInfo = GetTypeInfoInternal(typeToConvert, ensureConfigured: false, resolveIfMutable: tr
 064            return jsonTypeInfo.Converter;
 065        }
 66
 67        internal JsonConverter? GetConverterFromList(Type typeToConvert)
 1225468        {
 1225469            if (_converters is { } converterList)
 070            {
 071                foreach (JsonConverter item in converterList)
 072                {
 073                    if (item.CanConvert(typeToConvert))
 074                    {
 075                        return item;
 76                    }
 077                }
 078            }
 79
 1225480            return null;
 1225481        }
 82
 83        [return: NotNullIfNotNull(nameof(converter))]
 84        internal JsonConverter? ExpandConverterFactory(JsonConverter? converter, Type typeToConvert)
 3230285        {
 3230286            if (converter is JsonConverterFactory factory)
 391587            {
 391588                converter = factory.GetConverterInternal(typeToConvert, this);
 391589            }
 90
 3230291            return converter;
 3230292        }
 93
 94        internal static void CheckConverterNullabilityIsSameAsPropertyType(JsonConverter converter, Type propertyType)
 1225495        {
 96            // User has indicated that either:
 97            //   a) a non-nullable-struct handling converter should handle a nullable struct type or
 98            //   b) a nullable-struct handling converter should handle a non-nullable struct type.
 99            // User should implement a custom converter for the underlying struct and remove the unnecessary CanConvert 
 100            // The serializer will automatically wrap the custom converter with NullableConverter<T>.
 101            //
 102            // We also throw to avoid passing an invalid argument to setters for nullable struct properties,
 103            // which would cause an InvalidProgramException when the generated IL is invoked.
 12254104            if (propertyType.IsValueType && converter.IsValueType &&
 12254105                (propertyType.IsNullableOfT() ^ converter.Type!.IsNullableOfT()))
 0106            {
 0107                ThrowHelper.ThrowInvalidOperationException_ConverterCanConvertMultipleTypes(propertyType, converter);
 108            }
 12254109        }
 110    }
 111}

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializerOptions.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.ComponentModel;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Runtime.CompilerServices;
 9using System.Text.Encodings.Web;
 10using System.Text.Json.Nodes;
 11using System.Text.Json.Serialization;
 12using System.Text.Json.Serialization.Converters;
 13using System.Text.Json.Serialization.Metadata;
 14using System.Threading;
 15
 16namespace System.Text.Json
 17{
 18    /// <summary>
 19    /// Provides options to be used with <see cref="JsonSerializer"/>.
 20    /// </summary>
 21    [DebuggerDisplay("{DebuggerDisplay,nq}")]
 22    public sealed partial class JsonSerializerOptions
 23    {
 24        internal const int BufferSizeDefault = 16 * 1024;
 25
 26        // For backward compatibility the default max depth for JsonSerializer is 64,
 27        // the minimum of JsonReaderOptions.DefaultMaxDepth and JsonWriterOptions.DefaultMaxDepth.
 28        internal const int DefaultMaxDepth = JsonReaderOptions.DefaultMaxDepth;
 29
 30        /// <summary>
 31        /// Gets a read-only, singleton instance of <see cref="JsonSerializerOptions" /> that uses the default configura
 32        /// </summary>
 33        /// <remarks>
 34        /// Each <see cref="JsonSerializerOptions" /> instance encapsulates its own serialization metadata caches,
 35        /// so using fresh default instances every time one is needed can result in redundant recomputation of converter
 36        /// This property provides a shared instance that can be consumed by any number of components without necessitat
 37        /// </remarks>
 38        public static JsonSerializerOptions Default
 39        {
 40            [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 41            [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 042            get => field ?? GetOrCreateSingleton(ref field, JsonSerializerDefaults.General);
 43        }
 44
 45        /// <summary>
 46        /// Gets a read-only, singleton instance of <see cref="JsonSerializerOptions" /> that uses the web configuration
 47        /// </summary>
 48        /// <remarks>
 49        /// Each <see cref="JsonSerializerOptions" /> instance encapsulates its own serialization metadata caches,
 50        /// so using fresh default instances every time one is needed can result in redundant recomputation of converter
 51        /// This property provides a shared instance that can be consumed by any number of components without necessitat
 52        /// </remarks>
 53        public static JsonSerializerOptions Web
 54        {
 55            [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 56            [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 057            get => field ?? GetOrCreateSingleton(ref field, JsonSerializerDefaults.Web);
 58        }
 59
 60        /// <summary>
 61        /// Gets a read-only, singleton instance of <see cref="JsonSerializerOptions" /> that uses the strict configurat
 62        /// </summary>
 63        /// <remarks>
 64        /// Each <see cref="JsonSerializerOptions" /> instance encapsulates its own serialization metadata caches,
 65        /// so using fresh default instances every time one is needed can result in redundant recomputation of converter
 66        /// This property provides a shared instance that can be consumed by any number of components without necessitat
 67        /// </remarks>
 68        public static JsonSerializerOptions Strict
 69        {
 70            [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 71            [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 072            get => field ?? GetOrCreateSingleton(ref field, JsonSerializerDefaults.Strict);
 73        }
 74
 75        // For any new option added, consider adding it to the options copied in the copy constructor below
 76        // and consider updating the EqualtyComparer used for comparing CachingContexts.
 77        private IJsonTypeInfoResolver? _typeInfoResolver;
 78        private JsonNamingPolicy? _dictionaryKeyPolicy;
 79        private JsonNamingPolicy? _jsonPropertyNamingPolicy;
 80        private JsonCommentHandling _readCommentHandling;
 81        private ReferenceHandler? _referenceHandler;
 82        private JavaScriptEncoder? _encoder;
 83        private ConverterList? _converters;
 84        private JsonIgnoreCondition _defaultIgnoreCondition;
 85        private JsonNumberHandling _numberHandling;
 86        private JsonObjectCreationHandling _preferredObjectCreationHandling;
 87        private JsonUnknownTypeHandling _unknownTypeHandling;
 88        private JsonUnmappedMemberHandling _unmappedMemberHandling;
 89
 68290        private int _defaultBufferSize = BufferSizeDefault;
 91        private int _maxDepth;
 92        private bool _allowOutOfOrderMetadataProperties;
 93        private bool _allowTrailingCommas;
 68294        private bool _respectNullableAnnotations = AppContextSwitchHelper.RespectNullableAnnotationsDefault;
 68295        private bool _respectRequiredConstructorParameters = AppContextSwitchHelper.RespectRequiredConstructorParameters
 96        private bool _ignoreNullValues;
 97        private bool _ignoreReadOnlyProperties;
 98        private bool _ignoreReadonlyFields;
 99        private bool _includeFields;
 100        private string? _newLine;
 101        private bool _propertyNameCaseInsensitive;
 102        private bool _writeIndented;
 682103        private char _indentCharacter = JsonConstants.DefaultIndentCharacter;
 682104        private int _indentSize = JsonConstants.DefaultIndentSize;
 682105        private bool _allowDuplicateProperties = true;
 106
 107        /// <summary>
 108        /// Constructs a new <see cref="JsonSerializerOptions"/> instance.
 109        /// </summary>
 682110        public JsonSerializerOptions()
 682111        {
 682112            TrackOptionsInstance(this);
 682113        }
 114
 115        /// <summary>
 116        /// Copies the options from a <see cref="JsonSerializerOptions"/> instance to a new instance.
 117        /// </summary>
 118        /// <param name="options">The <see cref="JsonSerializerOptions"/> instance to copy options from.</param>
 119        /// <exception cref="System.ArgumentNullException">
 120        /// <paramref name="options"/> is <see langword="null"/>.
 121        /// </exception>
 0122        public JsonSerializerOptions(JsonSerializerOptions options)
 0123        {
 0124            ArgumentNullException.ThrowIfNull(options);
 125
 126            // The following fields are not copied intentionally:
 127            // 1. _cachingContext can only be set in immutable options instances.
 128            // 2. _typeInfoResolverChain can be created lazily as it relies on
 129            //    _typeInfoResolver as its source of truth.
 130
 0131            _dictionaryKeyPolicy = options._dictionaryKeyPolicy;
 0132            _jsonPropertyNamingPolicy = options._jsonPropertyNamingPolicy;
 0133            _readCommentHandling = options._readCommentHandling;
 0134            _referenceHandler = options._referenceHandler;
 0135            _converters = options._converters is { } converters ? new(this, converters) : null;
 0136            _encoder = options._encoder;
 0137            _defaultIgnoreCondition = options._defaultIgnoreCondition;
 0138            _numberHandling = options._numberHandling;
 0139            _preferredObjectCreationHandling = options._preferredObjectCreationHandling;
 0140            _unknownTypeHandling = options._unknownTypeHandling;
 0141            _unmappedMemberHandling = options._unmappedMemberHandling;
 142
 0143            _defaultBufferSize = options._defaultBufferSize;
 0144            _maxDepth = options._maxDepth;
 0145            _allowOutOfOrderMetadataProperties = options._allowOutOfOrderMetadataProperties;
 0146            _allowTrailingCommas = options._allowTrailingCommas;
 0147            _respectNullableAnnotations = options._respectNullableAnnotations;
 0148            _respectRequiredConstructorParameters = options._respectRequiredConstructorParameters;
 0149            _ignoreNullValues = options._ignoreNullValues;
 0150            _ignoreReadOnlyProperties = options._ignoreReadOnlyProperties;
 0151            _ignoreReadonlyFields = options._ignoreReadonlyFields;
 0152            _includeFields = options._includeFields;
 0153            _newLine = options._newLine;
 0154            _propertyNameCaseInsensitive = options._propertyNameCaseInsensitive;
 0155            _writeIndented = options._writeIndented;
 0156            _indentCharacter = options._indentCharacter;
 0157            _indentSize = options._indentSize;
 0158            _allowDuplicateProperties = options._allowDuplicateProperties;
 0159            _typeInfoResolver = options._typeInfoResolver;
 0160            EffectiveMaxDepth = options.EffectiveMaxDepth;
 0161            ReferenceHandlingStrategy = options.ReferenceHandlingStrategy;
 162
 0163            TrackOptionsInstance(this);
 0164        }
 165
 166        /// <summary>
 167        /// Constructs a new <see cref="JsonSerializerOptions"/> instance with a predefined set of options determined by
 168        /// </summary>
 169        /// <param name="defaults"> The <see cref="JsonSerializerDefaults"/> to reason about.</param>
 0170        public JsonSerializerOptions(JsonSerializerDefaults defaults) : this()
 0171        {
 172            // Should be kept in sync with equivalent overload in JsonSourceGenerationOptionsAttribute
 173
 0174            if (defaults == JsonSerializerDefaults.Web)
 0175            {
 0176                _propertyNameCaseInsensitive = true;
 0177                _jsonPropertyNamingPolicy = JsonNamingPolicy.CamelCase;
 0178                _numberHandling = JsonNumberHandling.AllowReadingFromString;
 0179            }
 0180            else if (defaults == JsonSerializerDefaults.Strict)
 0181            {
 0182                _unmappedMemberHandling = JsonUnmappedMemberHandling.Disallow;
 0183                _allowDuplicateProperties = false;
 0184                _respectNullableAnnotations = true;
 0185                _respectRequiredConstructorParameters = true;
 0186            }
 0187            else if (defaults != JsonSerializerDefaults.General)
 0188            {
 0189                throw new ArgumentOutOfRangeException(nameof(defaults));
 190            }
 0191        }
 192
 193        /// <summary>Tracks the options instance to enable all instances to be enumerated.</summary>
 682194        private static void TrackOptionsInstance(JsonSerializerOptions options) => TrackedOptionsInstances.All.Add(optio
 195
 196        internal static class TrackedOptionsInstances
 197        {
 198            /// <summary>Tracks all live JsonSerializerOptions instances.</summary>
 199            /// <remarks>Instances are added to the table in their constructor.</remarks>
 682200            public static ConditionalWeakTable<JsonSerializerOptions, object?> All { get; } =
 201                // TODO https://github.com/dotnet/runtime/issues/51159:
 202                // Look into linking this away / disabling it when hot reload isn't in use.
 1203                new ConditionalWeakTable<JsonSerializerOptions, object?>();
 204        }
 205
 206        /// <summary>
 207        /// Binds current <see cref="JsonSerializerOptions"/> instance with a new instance of the specified <see cref="S
 208        /// </summary>
 209        /// <typeparam name="TContext">The generic definition of the specified context type.</typeparam>
 210        /// <remarks>
 211        /// When serializing and deserializing types using the options
 212        /// instance, metadata for the types will be fetched from the context instance.
 213        /// </remarks>
 214        [Obsolete(Obsoletions.JsonSerializerOptionsAddContextMessage, DiagnosticId = Obsoletions.JsonSerializerOptionsAd
 215        [EditorBrowsable(EditorBrowsableState.Never)]
 216        public void AddContext<TContext>() where TContext : JsonSerializerContext, new()
 0217        {
 0218            VerifyMutable();
 0219            TContext context = new();
 0220            context.AssociateWithOptions(this);
 0221        }
 222
 223        /// <summary>
 224        /// Gets or sets the <see cref="JsonTypeInfo"/> contract resolver used by this instance.
 225        /// </summary>
 226        /// <exception cref="InvalidOperationException">
 227        /// Thrown if this property is set after serialization or deserialization has occurred.
 228        /// </exception>
 229        /// <remarks>
 230        /// A <see langword="null"/> setting is equivalent to using the reflection-based <see cref="DefaultJsonTypeInfoR
 231        /// The property will be populated automatically once used with one of the <see cref="JsonSerializer"/> methods.
 232        ///
 233        /// This property is kept in sync with the <see cref="TypeInfoResolverChain"/> property.
 234        /// Any change made to this property will be reflected by <see cref="TypeInfoResolverChain"/> and vice versa.
 235        /// </remarks>
 236        public IJsonTypeInfoResolver? TypeInfoResolver
 237        {
 238            get
 12523239            {
 12523240                return _typeInfoResolver;
 12523241            }
 242            set
 0243            {
 0244                VerifyMutable();
 245
 0246                if (_typeInfoResolverChain is { } resolverChain && !ReferenceEquals(resolverChain, value))
 0247                {
 248                    // User is setting a new resolver; detach the resolver chain if already created.
 0249                    resolverChain.DetachFromOptions();
 0250                    _typeInfoResolverChain = null;
 0251                }
 252
 0253                _typeInfoResolver = value;
 0254            }
 255        }
 256
 257        /// <summary>
 258        /// Gets the list of chained <see cref="JsonTypeInfo"/> contract resolvers used by this instance.
 259        /// </summary>
 260        /// <remarks>
 261        /// The ordering of the chain is significant: <see cref="JsonSerializerOptions "/> will query each
 262        /// of the resolvers in their specified order, returning the first result that is non-null.
 263        /// If all resolvers in the chain return null, then <see cref="JsonSerializerOptions"/> will also return null.
 264        ///
 265        /// This property is auxiliary to and is kept in sync with the <see cref="TypeInfoResolver"/> property.
 266        /// Any change made to this property will be reflected by <see cref="TypeInfoResolver"/> and vice versa.
 267        /// </remarks>
 0268        public IList<IJsonTypeInfoResolver> TypeInfoResolverChain => _typeInfoResolverChain ??= new(this);
 269        private OptionsBoundJsonTypeInfoResolverChain? _typeInfoResolverChain;
 270
 271        /// <summary>
 272        /// Allows JSON metadata properties to be specified after regular properties in a deserialized JSON object.
 273        /// </summary>
 274        /// <exception cref="InvalidOperationException">
 275        /// Thrown if this property is set after serialization or deserialization has occurred.
 276        /// </exception>
 277        /// <remarks>
 278        /// When set to <see langword="true" />, removes the requirement that JSON metadata properties
 279        /// such as $id and $type should be specified at the very start of the deserialized JSON object.
 280        ///
 281        /// It should be noted that enabling this setting can result in over-buffering
 282        /// when deserializing large JSON payloads in the context of streaming deserialization.
 283        /// </remarks>
 284        public bool AllowOutOfOrderMetadataProperties
 285        {
 286            get
 0287            {
 0288                return _allowOutOfOrderMetadataProperties;
 0289            }
 290            set
 0291            {
 0292                VerifyMutable();
 0293                _allowOutOfOrderMetadataProperties = value;
 0294            }
 295        }
 296
 297        /// <summary>
 298        /// Defines whether an extra comma at the end of a list of JSON values in an object or array
 299        /// is allowed (and ignored) within the JSON payload being deserialized.
 300        /// </summary>
 301        /// <exception cref="InvalidOperationException">
 302        /// Thrown if this property is set after serialization or deserialization has occurred.
 303        /// </exception>
 304        /// <remarks>
 305        /// By default, it's set to false, and <exception cref="JsonException"/> is thrown if a trailing comma is encoun
 306        /// </remarks>
 307        public bool AllowTrailingCommas
 308        {
 309            get
 55924310            {
 55924311                return _allowTrailingCommas;
 55924312            }
 313            set
 682314            {
 682315                VerifyMutable();
 682316                _allowTrailingCommas = value;
 682317            }
 318        }
 319
 320        /// <summary>
 321        /// The default buffer size in bytes used when creating temporary buffers.
 322        /// </summary>
 323        /// <remarks>The default size is 16K.</remarks>
 324        /// <exception cref="System.ArgumentException">Thrown when the buffer size is less than 1.</exception>
 325        /// <exception cref="InvalidOperationException">
 326        /// Thrown if this property is set after serialization or deserialization has occurred.
 327        /// </exception>
 328        public int DefaultBufferSize
 329        {
 330            get
 27962331            {
 27962332                return _defaultBufferSize;
 27962333            }
 334            set
 0335            {
 0336                VerifyMutable();
 337
 0338                if (value < 1)
 0339                {
 0340                    throw new ArgumentException(SR.SerializationInvalidBufferSize);
 341                }
 342
 0343                _defaultBufferSize = value;
 0344            }
 345        }
 346
 347        /// <summary>
 348        /// The encoder to use when escaping strings, or <see langword="null" /> to use the default encoder.
 349        /// </summary>
 350        public JavaScriptEncoder? Encoder
 351        {
 352            get
 8332353            {
 8332354                return _encoder;
 8332355            }
 356            set
 682357            {
 682358                VerifyMutable();
 359
 682360                _encoder = value;
 682361            }
 362        }
 363
 364        /// <summary>
 365        /// Specifies the policy used to convert a <see cref="System.Collections.IDictionary"/> key's name to another fo
 366        /// </summary>
 367        /// <remarks>
 368        /// This property can be set to <see cref="JsonNamingPolicy.CamelCase"/> to specify a camel-casing policy.
 369        /// It is not used when deserializing.
 370        /// </remarks>
 371        public JsonNamingPolicy? DictionaryKeyPolicy
 372        {
 373            get
 0374            {
 0375                return _dictionaryKeyPolicy;
 0376            }
 377            set
 0378            {
 0379                VerifyMutable();
 0380                _dictionaryKeyPolicy = value;
 0381            }
 382        }
 383
 384        /// <summary>
 385        /// Determines whether null values are ignored during serialization and deserialization.
 386        /// The default value is false.
 387        /// </summary>
 388        /// <exception cref="InvalidOperationException">
 389        /// Thrown if this property is set after serialization or deserialization has occurred.
 390        /// or <see cref="DefaultIgnoreCondition"/> has been set to a non-default value. These properties cannot be used
 391        /// </exception>
 392        [Obsolete(Obsoletions.JsonSerializerOptionsIgnoreNullValuesMessage, DiagnosticId = Obsoletions.JsonSerializerOpt
 393        [EditorBrowsable(EditorBrowsableState.Never)]
 394        public bool IgnoreNullValues
 395        {
 396            get
 20048397            {
 20048398                return _ignoreNullValues;
 20048399            }
 400            set
 0401            {
 0402                VerifyMutable();
 403
 0404                if (value && _defaultIgnoreCondition != JsonIgnoreCondition.Never)
 0405                {
 0406                    throw new InvalidOperationException(SR.DefaultIgnoreConditionAlreadySpecified);
 407                }
 408
 0409                _ignoreNullValues = value;
 0410            }
 411        }
 412
 413        /// <summary>
 414        /// Specifies a condition to determine when properties with default values are ignored during serialization or d
 415        /// The default value is <see cref="JsonIgnoreCondition.Never" />.
 416        /// </summary>
 417        /// <exception cref="ArgumentException">
 418        /// Thrown if this property is set to <see cref="JsonIgnoreCondition.Always"/>.
 419        /// </exception>
 420        /// <exception cref="InvalidOperationException">
 421        /// Thrown if this property is set after serialization or deserialization has occurred,
 422        /// or <see cref="IgnoreNullValues"/> has been set to <see langword="true"/>. These properties cannot be used to
 423        /// </exception>
 424        public JsonIgnoreCondition DefaultIgnoreCondition
 425        {
 426            get
 40096427            {
 40096428                return _defaultIgnoreCondition;
 40096429            }
 430            set
 0431            {
 0432                VerifyMutable();
 433
 0434                if (value == JsonIgnoreCondition.Always)
 0435                {
 0436                    throw new ArgumentException(SR.DefaultIgnoreConditionInvalid);
 437                }
 438
 0439                if (value != JsonIgnoreCondition.Never && _ignoreNullValues)
 0440                {
 0441                    throw new InvalidOperationException(SR.DefaultIgnoreConditionAlreadySpecified);
 442                }
 443
 0444                _defaultIgnoreCondition = value;
 0445            }
 446        }
 447
 448        /// <summary>
 449        /// Specifies how number types should be handled when serializing or deserializing.
 450        /// </summary>
 451        /// <exception cref="InvalidOperationException">
 452        /// Thrown if this property is set after serialization or deserialization has occurred.
 453        /// </exception>
 454        public JsonNumberHandling NumberHandling
 455        {
 21771456            get => _numberHandling;
 457            set
 682458            {
 682459                VerifyMutable();
 460
 682461                if (!JsonSerializer.IsValidNumberHandlingValue(value))
 0462                {
 0463                    throw new ArgumentOutOfRangeException(nameof(value));
 464                }
 682465                _numberHandling = value;
 682466            }
 467        }
 468
 469        /// <summary>
 470        /// Specifies preferred object creation handling for properties when deserializing JSON.
 471        /// When set to <see cref="JsonObjectCreationHandling.Populate"/> all properties which
 472        /// are capable of reusing the existing instance will be populated.
 473        /// </summary>
 474        /// <remarks>
 475        /// Only property type is taken into consideration. For example if property is of type
 476        /// <see cref="IEnumerable{T}"/> but it is assigned <see cref="List{T}"/> it will not be populated
 477        /// because <see cref="IEnumerable{T}"/> is not capable of populating.
 478        /// Additionally value types require a setter to be populated.
 479        /// </remarks>
 480        public JsonObjectCreationHandling PreferredObjectCreationHandling
 481        {
 14805482            get => _preferredObjectCreationHandling;
 483            set
 0484            {
 0485                VerifyMutable();
 486
 0487                if (!JsonSerializer.IsValidCreationHandlingValue(value))
 0488                {
 0489                    throw new ArgumentOutOfRangeException(nameof(value));
 490                }
 491
 0492                _preferredObjectCreationHandling = value;
 0493            }
 494        }
 495
 496        /// <summary>
 497        /// Determines whether read-only properties are ignored during serialization.
 498        /// A property is read-only if it contains a public getter but not a public setter.
 499        /// The default value is false.
 500        /// </summary>
 501        /// <remarks>
 502        /// Read-only properties are not deserialized regardless of this setting.
 503        /// </remarks>
 504        /// <exception cref="InvalidOperationException">
 505        /// Thrown if this property is set after serialization or deserialization has occurred.
 506        /// </exception>
 507        public bool IgnoreReadOnlyProperties
 508        {
 509            get
 0510            {
 0511                return _ignoreReadOnlyProperties;
 0512            }
 513            set
 0514            {
 0515                VerifyMutable();
 0516                _ignoreReadOnlyProperties = value;
 0517            }
 518        }
 519
 520        /// <summary>
 521        /// Determines whether read-only fields are ignored during serialization.
 522        /// A field is read-only if it is marked with the <c>readonly</c> keyword.
 523        /// The default value is false.
 524        /// </summary>
 525        /// <remarks>
 526        /// Read-only fields are not deserialized regardless of this setting.
 527        /// </remarks>
 528        /// <exception cref="InvalidOperationException">
 529        /// Thrown if this property is set after serialization or deserialization has occurred.
 530        /// </exception>
 531        public bool IgnoreReadOnlyFields
 532        {
 533            get
 0534            {
 0535                return _ignoreReadonlyFields;
 0536            }
 537            set
 0538            {
 0539                VerifyMutable();
 0540                _ignoreReadonlyFields = value;
 0541            }
 542        }
 543
 544        /// <summary>
 545        /// Determines whether fields are handled on serialization and deserialization.
 546        /// The default value is false.
 547        /// </summary>
 548        /// <exception cref="InvalidOperationException">
 549        /// Thrown if this property is set after serialization or deserialization has occurred.
 550        /// </exception>
 551        public bool IncludeFields
 552        {
 553            get
 0554            {
 0555                return _includeFields;
 0556            }
 557            set
 0558            {
 0559                VerifyMutable();
 0560                _includeFields = value;
 0561            }
 562        }
 563
 564        /// <summary>
 565        /// Gets or sets the maximum depth allowed when serializing or deserializing JSON, with the default (i.e. 0) ind
 566        /// </summary>
 567        /// <exception cref="InvalidOperationException">
 568        /// Thrown if this property is set after serialization or deserialization has occurred.
 569        /// </exception>
 570        /// <exception cref="ArgumentOutOfRangeException">
 571        /// Thrown when the max depth is set to a negative value.
 572        /// </exception>
 573        /// <remarks>
 574        /// Going past this depth will throw a <exception cref="JsonException"/>.
 575        /// </remarks>
 576        public int MaxDepth
 577        {
 0578            get => _maxDepth;
 579            set
 0580            {
 0581                VerifyMutable();
 582
 0583                if (value < 0)
 0584                {
 0585                    ThrowHelper.ThrowArgumentOutOfRangeException_MaxDepthMustBePositive(nameof(value));
 586                }
 587
 0588                _maxDepth = value;
 0589                EffectiveMaxDepth = (value == 0 ? DefaultMaxDepth : value);
 0590            }
 591        }
 592
 56606593        internal int EffectiveMaxDepth { get; private set; } = DefaultMaxDepth;
 594
 595        /// <summary>
 596        /// Specifies the policy used to convert a property's name on an object to another format, such as camel-casing.
 597        /// The resulting property name is expected to match the JSON payload during deserialization, and
 598        /// will be used when writing the property name during serialization.
 599        /// </summary>
 600        /// <remarks>
 601        /// The policy is not used for properties that have a <see cref="JsonPropertyNameAttribute"/> applied.
 602        /// This property can be set to <see cref="JsonNamingPolicy.CamelCase"/> to specify a camel-casing policy.
 603        /// </remarks>
 604        public JsonNamingPolicy? PropertyNamingPolicy
 605        {
 606            get
 7794607            {
 7794608                return _jsonPropertyNamingPolicy;
 7794609            }
 610            set
 0611            {
 0612                VerifyMutable();
 0613                _jsonPropertyNamingPolicy = value;
 0614            }
 615        }
 616
 617        /// <summary>
 618        /// Determines whether a property's name uses a case-insensitive comparison during deserialization.
 619        /// The default value is false.
 620        /// </summary>
 621        /// <remarks>There is a performance cost associated when the value is true.</remarks>
 622        public bool PropertyNameCaseInsensitive
 623        {
 624            get
 3888625            {
 3888626                return _propertyNameCaseInsensitive;
 3888627            }
 628            set
 0629            {
 0630                VerifyMutable();
 0631                _propertyNameCaseInsensitive = value;
 0632            }
 633        }
 634
 635        /// <summary>
 636        /// Defines how the comments are handled during deserialization.
 637        /// </summary>
 638        /// <exception cref="InvalidOperationException">
 639        /// Thrown if this property is set after serialization or deserialization has occurred.
 640        /// </exception>
 641        /// <exception cref="ArgumentOutOfRangeException">
 642        /// Thrown when the comment handling enum is set to a value that is not supported (or not within the <see cref="
 643        /// </exception>
 644        /// <remarks>
 645        /// By default <exception cref="JsonException"/> is thrown if a comment is encountered.
 646        /// </remarks>
 647        public JsonCommentHandling ReadCommentHandling
 648        {
 649            get
 55924650            {
 55924651                return _readCommentHandling;
 55924652            }
 653            set
 682654            {
 682655                VerifyMutable();
 656
 682657                Debug.Assert(value >= 0);
 682658                if (value > JsonCommentHandling.Skip)
 0659                    throw new ArgumentOutOfRangeException(nameof(value), SR.JsonSerializerDoesNotSupportComments);
 660
 682661                _readCommentHandling = value;
 682662            }
 663        }
 664
 665        /// <summary>
 666        /// Defines how deserializing a type declared as an <see cref="object"/> is handled during deserialization.
 667        /// </summary>
 668        public JsonUnknownTypeHandling UnknownTypeHandling
 669        {
 634670            get => _unknownTypeHandling;
 671            set
 0672            {
 0673                VerifyMutable();
 0674                _unknownTypeHandling = value;
 0675            }
 676        }
 677
 678        /// <summary>
 679        /// Determines how <see cref="JsonSerializer"/> handles JSON properties that
 680        /// cannot be mapped to a specific .NET member when deserializing object types.
 681        /// </summary>
 682        public JsonUnmappedMemberHandling UnmappedMemberHandling
 683        {
 1299684            get => _unmappedMemberHandling;
 685            set
 0686            {
 0687                VerifyMutable();
 0688                _unmappedMemberHandling = value;
 0689            }
 690        }
 691
 692        /// <summary>
 693        /// Defines whether JSON should pretty print which includes:
 694        /// indenting nested JSON tokens, adding new lines, and adding white space between property names and values.
 695        /// By default, the JSON is serialized without any extra white space.
 696        /// </summary>
 697        /// <exception cref="InvalidOperationException">
 698        /// Thrown if this property is set after serialization or deserialization has occurred.
 699        /// </exception>
 700        public bool WriteIndented
 701        {
 702            get
 0703            {
 0704                return _writeIndented;
 0705            }
 706            set
 0707            {
 0708                VerifyMutable();
 0709                _writeIndented = value;
 0710            }
 711        }
 712
 713        /// <summary>
 714        /// Defines the indentation character being used when <see cref="WriteIndented" /> is enabled. Defaults to the s
 715        /// </summary>
 716        /// <remarks>Allowed characters are space and horizontal tab.</remarks>
 717        /// <exception cref="ArgumentOutOfRangeException"><paramref name="value"/> contains an invalid character.</excep
 718        /// <exception cref="InvalidOperationException">
 719        /// Thrown if this property is set after serialization or deserialization has occurred.
 720        /// </exception>
 721        public char IndentCharacter
 722        {
 723            get
 0724            {
 0725                return _indentCharacter;
 0726            }
 727            set
 0728            {
 0729                JsonWriterHelper.ValidateIndentCharacter(value);
 0730                VerifyMutable();
 0731                _indentCharacter = value;
 0732            }
 733        }
 734
 735        /// <summary>
 736        /// Defines the indentation size being used when <see cref="WriteIndented" /> is enabled. Defaults to two.
 737        /// </summary>
 738        /// <remarks>Allowed values are all integers between 0 and 127, included.</remarks>
 739        /// <exception cref="ArgumentOutOfRangeException"><paramref name="value"/> is out of the allowed range.</excepti
 740        /// <exception cref="InvalidOperationException">
 741        /// Thrown if this property is set after serialization or deserialization has occurred.
 742        /// </exception>
 743        public int IndentSize
 744        {
 745            get
 0746            {
 0747                return _indentSize;
 0748            }
 749            set
 0750            {
 0751                JsonWriterHelper.ValidateIndentSize(value);
 0752                VerifyMutable();
 0753                _indentSize = value;
 0754            }
 755        }
 756
 757        /// <summary>
 758        /// Configures how object references are handled when reading and writing JSON.
 759        /// </summary>
 760        public ReferenceHandler? ReferenceHandler
 761        {
 0762            get => _referenceHandler;
 763            set
 0764            {
 0765                VerifyMutable();
 0766                _referenceHandler = value;
 0767                ReferenceHandlingStrategy = value?.HandlingStrategy ?? JsonKnownReferenceHandler.Unspecified;
 0768            }
 769        }
 770
 771        /// <summary>
 772        /// Gets or sets the new line string to use when <see cref="WriteIndented"/> is <see langword="true"/>.
 773        /// The default is the value of <see cref="Environment.NewLine"/>.
 774        /// </summary>
 775        /// <exception cref="ArgumentNullException">
 776        /// Thrown when the new line string is <see langword="null"/>.
 777        /// </exception>
 778        /// <exception cref="ArgumentOutOfRangeException">
 779        /// Thrown when the new line string is not <c>\n</c> or <c>\r\n</c>.
 780        /// </exception>
 781        /// <exception cref="InvalidOperationException">
 782        /// Thrown if this property is set after serialization or deserialization has occurred.
 783        /// </exception>
 784        public string NewLine
 785        {
 786            get
 1508787            {
 1508788                return _newLine ??= Environment.NewLine;
 1508789            }
 790            set
 0791            {
 0792                JsonWriterHelper.ValidateNewLine(value);
 0793                VerifyMutable();
 0794                _newLine = value;
 0795            }
 796        }
 797
 798        /// <summary>
 799        /// Gets or sets a value that indicates whether nullability annotations should be respected during serialization
 800        /// </summary>
 801        /// <exception cref="InvalidOperationException">
 802        /// Thrown if this property is set after serialization or deserialization has occurred.
 803        /// </exception>
 804        /// <remarks>
 805        /// Nullability annotations are resolved from the properties, fields and constructor parameters
 806        /// that are used by the serializer. This includes annotations stemming from attributes such as
 807        /// <see cref="NotNullAttribute"/>, <see cref="MaybeNullAttribute"/>,
 808        /// <see cref="AllowNullAttribute"/> and <see cref="DisallowNullAttribute"/>.
 809        ///
 810        /// Due to restrictions in how nullable reference types are represented at run time,
 811        /// this setting only governs nullability annotations of non-generic properties and fields.
 812        /// It cannot be used to enforce nullability annotations of root-level types or generic parameters.
 813        ///
 814        /// The default setting for this property can be toggled application-wide using the
 815        /// "System.Text.Json.Serialization.RespectNullableAnnotationsDefault" feature switch.
 816        /// </remarks>
 817        public bool RespectNullableAnnotations
 818        {
 0819            get => _respectNullableAnnotations;
 820            set
 0821            {
 0822                VerifyMutable();
 0823                _respectNullableAnnotations = value;
 0824            }
 825        }
 826
 827        /// <summary>
 828        /// Gets or sets a value that indicates whether non-optional constructor parameters should be specified during d
 829        /// </summary>
 830        /// <exception cref="InvalidOperationException">
 831        /// Thrown if this property is set after serialization or deserialization has occurred.
 832        /// </exception>
 833        /// <remarks>
 834        /// For historical reasons constructor-based deserialization treats all constructor parameters as optional by de
 835        /// This flag allows users to toggle that behavior as necessary for each <see cref="JsonSerializerOptions"/> ins
 836        ///
 837        /// The default setting for this property can be toggled application-wide using the
 838        /// "System.Text.Json.Serialization.RespectRequiredConstructorParametersDefault" feature switch.
 839        /// </remarks>
 840        public bool RespectRequiredConstructorParameters
 841        {
 4494842            get => _respectRequiredConstructorParameters;
 843            set
 0844            {
 0845                VerifyMutable();
 0846                _respectRequiredConstructorParameters = value;
 0847            }
 848        }
 849
 850        /// <summary>
 851        /// Defines whether duplicate property names are allowed when deserializing JSON objects.
 852        /// </summary>
 853        /// <exception cref="InvalidOperationException">
 854        /// Thrown if this property is set after serialization or deserialization has occurred.
 855        /// </exception>
 856        /// <remarks>
 857        /// <para>
 858        /// By default, it's set to true. If set to false, <see cref="JsonException"/> is thrown
 859        /// when a duplicate property name is encountered during deserialization.
 860        /// </para>
 861        /// <para>
 862        /// Duplicate property names are not allowed in serialization.
 863        /// </para>
 864        /// </remarks>
 865        public bool AllowDuplicateProperties
 866        {
 3050867            get => _allowDuplicateProperties;
 868            set
 0869            {
 0870                VerifyMutable();
 0871                _allowDuplicateProperties = value;
 0872            }
 873        }
 874
 875        /// <summary>
 876        /// Returns true if options uses compatible built-in resolvers or a combination of compatible built-in resolvers
 877        /// </summary>
 878        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 879        internal bool CanUseFastPathSerializationLogic
 880        {
 881            get
 12254882            {
 12254883                Debug.Assert(IsReadOnly);
 12254884                Debug.Assert(TypeInfoResolver != null);
 12254885                return _canUseFastPathSerializationLogic ??= TypeInfoResolver.IsCompatibleWithOptions(this);
 12254886            }
 887        }
 888
 889        private bool? _canUseFastPathSerializationLogic;
 890
 891        // The cached value used to determine if ReferenceHandler should use Preserve or IgnoreCycles semantics or None 
 682892        internal JsonKnownReferenceHandler ReferenceHandlingStrategy = JsonKnownReferenceHandler.Unspecified;
 893
 894        /// <summary>
 895        /// Specifies whether the current instance has been locked for user modification.
 896        /// </summary>
 897        /// <remarks>
 898        /// A <see cref="JsonSerializerOptions"/> instance can be locked either if
 899        /// it has been passed to one of the <see cref="JsonSerializer"/> methods,
 900        /// has been associated with a <see cref="JsonSerializerContext"/> instance,
 901        /// or a user explicitly called the <see cref="MakeReadOnly()"/> methods on the instance.
 902        ///
 903        /// Read-only instances use caching when querying <see cref="JsonConverter"/> and <see cref="JsonTypeInfo"/> met
 904        /// </remarks>
 180374905        public bool IsReadOnly => _isReadOnly;
 906        private volatile bool _isReadOnly;
 907
 908        /// <summary>
 909        /// Marks the current instance as read-only preventing any further user modification.
 910        /// </summary>
 911        /// <exception cref="InvalidOperationException">The instance does not specify a <see cref="TypeInfoResolver"/> s
 912        /// <remarks>This method is idempotent.</remarks>
 913        public void MakeReadOnly()
 24508914        {
 24508915            if (_typeInfoResolver is null)
 0916            {
 0917                ThrowHelper.ThrowInvalidOperationException_JsonSerializerOptionsNoTypeInfoResolverSpecified();
 918            }
 919
 24508920            _isReadOnly = true;
 24508921        }
 922
 923        /// <summary>
 924        /// Marks the current instance as read-only preventing any further user modification.
 925        /// </summary>
 926        /// <param name="populateMissingResolver">Populates unconfigured <see cref="TypeInfoResolver"/> properties with 
 927        /// <exception cref="InvalidOperationException">
 928        /// The instance does not specify a <see cref="TypeInfoResolver"/> setting. Thrown if <paramref name="populateMi
 929        /// -OR-
 930        /// The <see cref="JsonSerializer.IsReflectionEnabledByDefault"/> feature switch has been turned off.
 931        /// </exception>
 932        /// <remarks>
 933        /// When <paramref name="populateMissingResolver"/> is set to <see langword="true" />, configures the instance f
 934        /// the semantics of the <see cref="JsonSerializer"/> methods accepting <see cref="JsonSerializerOptions"/> para
 935        ///
 936        /// This method is idempotent.
 937        /// </remarks>
 938        [RequiresUnreferencedCode("Populating unconfigured TypeInfoResolver properties with the reflection resolver requ
 939        [RequiresDynamicCode("Populating unconfigured TypeInfoResolver properties with the reflection resolver requires 
 940        public void MakeReadOnly(bool populateMissingResolver)
 55924941        {
 55924942            if (populateMissingResolver)
 55924943            {
 55924944                if (!_isConfiguredForJsonSerializer)
 682945                {
 682946                    ConfigureForJsonSerializer();
 682947                }
 55924948            }
 949            else
 0950            {
 0951                MakeReadOnly();
 0952            }
 953
 55924954            Debug.Assert(IsReadOnly);
 55924955        }
 956
 957        /// <summary>
 958        /// Configures the instance for use by the JsonSerializer APIs, applying reflection-based fallback where applica
 959        /// </summary>
 960        [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 961        [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 962        private void ConfigureForJsonSerializer()
 682963        {
 682964            if (JsonSerializer.IsReflectionEnabledByDefault)
 682965            {
 966                // Even if a resolver has already been specified, we need to root
 967                // the default resolver to gain access to the default converters.
 682968                DefaultJsonTypeInfoResolver defaultResolver = DefaultJsonTypeInfoResolver.DefaultInstance;
 969
 682970                switch (_typeInfoResolver)
 971                {
 972                    case null:
 973                        // Use the default reflection-based resolver if no resolver has been specified.
 682974                        _typeInfoResolver = defaultResolver;
 682975                        break;
 976
 0977                    case JsonSerializerContext ctx when AppContextSwitchHelper.IsSourceGenReflectionFallbackEnabled:
 978                        // .NET 6 compatibility mode: enable fallback to reflection metadata for JsonSerializerContext
 0979                        _effectiveJsonTypeInfoResolver = JsonTypeInfoResolver.Combine(ctx, defaultResolver);
 980
 0981                        if (_cachingContext is { } cachingContext)
 0982                        {
 983                            // A cache has already been created by the source generator.
 984                            // Repeat the same configuration routine for that options instance, if different.
 985                            // Invalidate any cache entries that have already been stored.
 0986                            if (cachingContext.Options != this && !cachingContext.Options._isConfiguredForJsonSerializer
 0987                            {
 0988                                cachingContext.Options.ConfigureForJsonSerializer();
 0989                            }
 990                            else
 0991                            {
 0992                                cachingContext.Clear();
 0993                            }
 0994                        }
 0995                        break;
 996                }
 682997            }
 0998            else if (_typeInfoResolver is null or EmptyJsonTypeInfoResolver)
 0999            {
 01000                ThrowHelper.ThrowInvalidOperationException_JsonSerializerIsReflectionDisabled();
 1001            }
 1002
 6821003            Debug.Assert(_typeInfoResolver != null);
 1004            // NB preserve write order.
 6821005            _isReadOnly = true;
 6821006            _isConfiguredForJsonSerializer = true;
 6821007        }
 1008
 1009        /// <summary>
 1010        /// This flag is supplementary to <see cref="_isReadOnly"/> and is only used to keep track
 1011        /// of source-gen reflection fallback (assuming the IsSourceGenReflectionFallbackEnabled feature switch is on).
 1012        /// This mode necessitates running the <see cref="ConfigureForJsonSerializer"/> method even
 1013        /// for options instances that have been marked as read-only.
 1014        /// </summary>
 1015        private volatile bool _isConfiguredForJsonSerializer;
 1016
 1017        // Only populated in .NET 6 compatibility mode encoding reflection fallback in source gen
 1018        private IJsonTypeInfoResolver? _effectiveJsonTypeInfoResolver;
 1019
 1020        private JsonTypeInfo? GetTypeInfoNoCaching(Type type)
 122541021        {
 122541022            IJsonTypeInfoResolver? resolver = _effectiveJsonTypeInfoResolver ?? _typeInfoResolver;
 122541023            if (resolver is null)
 01024            {
 01025                return null;
 1026            }
 1027
 122541028            JsonTypeInfo? info = resolver.GetTypeInfo(type, this);
 1029
 122541030            if (info != null)
 122541031            {
 122541032                if (info.Type != type)
 01033                {
 01034                    ThrowHelper.ThrowInvalidOperationException_ResolverTypeNotCompatible(type, info.Type);
 1035                }
 1036
 122541037                if (info.Options != this)
 01038                {
 01039                    ThrowHelper.ThrowInvalidOperationException_ResolverTypeInfoOptionsNotCompatible();
 1040                }
 122541041            }
 1042            else
 01043            {
 01044                Debug.Assert(_effectiveJsonTypeInfoResolver is null, "an effective resolver always returns metadata");
 1045
 01046                if (type == JsonTypeInfo.ObjectType)
 01047                {
 1048                    // If the resolver does not provide a JsonTypeInfo<object> instance, fill
 1049                    // with the serialization-only converter to enable polymorphic serialization.
 01050                    var converter = new SlimObjectConverter(resolver);
 01051                    info = new JsonTypeInfo<object>(converter, this);
 01052                }
 01053            }
 1054
 122541055            return info;
 122541056        }
 1057
 1058        internal JsonDocumentOptions GetDocumentOptions()
 01059        {
 01060            return new JsonDocumentOptions
 01061            {
 01062                AllowDuplicateProperties = AllowDuplicateProperties,
 01063                AllowTrailingCommas = AllowTrailingCommas,
 01064                CommentHandling = ReadCommentHandling,
 01065                MaxDepth = MaxDepth,
 01066            };
 01067        }
 1068
 1069        internal JsonNodeOptions GetNodeOptions()
 12901070        {
 12901071            return new JsonNodeOptions
 12901072            {
 12901073                PropertyNameCaseInsensitive = PropertyNameCaseInsensitive
 12901074            };
 12901075        }
 1076
 1077        internal JsonReaderOptions GetReaderOptions()
 559241078        {
 559241079            return new JsonReaderOptions
 559241080            {
 559241081                AllowTrailingCommas = AllowTrailingCommas,
 559241082                CommentHandling = ReadCommentHandling,
 559241083                MaxDepth = EffectiveMaxDepth
 559241084            };
 559241085        }
 1086
 1087        internal JsonWriterOptions GetWriterOptions()
 01088        {
 01089            return new JsonWriterOptions
 01090            {
 01091                Encoder = Encoder,
 01092                Indented = WriteIndented,
 01093                IndentCharacter = IndentCharacter,
 01094                IndentSize = IndentSize,
 01095                MaxDepth = EffectiveMaxDepth,
 01096                NewLine = NewLine,
 01097#if !DEBUG
 01098                SkipValidation = true
 01099#endif
 01100            };
 01101        }
 1102
 1103        internal void VerifyMutable()
 27281104        {
 27281105            if (_isReadOnly)
 01106            {
 01107                ThrowHelper.ThrowInvalidOperationException_SerializerOptionsReadOnly(_typeInfoResolver as JsonSerializer
 1108            }
 27281109        }
 1110
 1111        private sealed class ConverterList : ConfigurationList<JsonConverter>
 1112        {
 1113            private readonly JsonSerializerOptions _options;
 1114
 1115            public ConverterList(JsonSerializerOptions options, IList<JsonConverter>? source = null)
 01116                : base(source)
 01117            {
 01118                _options = options;
 01119            }
 1120
 01121            public override bool IsReadOnly => _options.IsReadOnly;
 01122            protected override void OnCollectionModifying() => _options.VerifyMutable();
 1123        }
 1124
 1125        private sealed class OptionsBoundJsonTypeInfoResolverChain : JsonTypeInfoResolverChain
 1126        {
 1127            private JsonSerializerOptions? _options;
 1128
 01129            public OptionsBoundJsonTypeInfoResolverChain(JsonSerializerOptions options)
 01130            {
 01131                _options = options;
 01132                AddFlattened(options._typeInfoResolver);
 01133            }
 1134
 1135            public void DetachFromOptions()
 01136            {
 01137                _options = null;
 01138            }
 1139
 01140            public override bool IsReadOnly => _options?.IsReadOnly is true;
 1141
 1142            protected override void ValidateAddedValue(IJsonTypeInfoResolver item)
 01143            {
 01144                Debug.Assert(item is not null);
 1145
 01146                if (ReferenceEquals(item, this) || ReferenceEquals(item, _options?._typeInfoResolver))
 01147                {
 1148                    // Cannot add the instances in TypeInfoResolver or TypeInfoResolverChain to the chain itself.
 01149                    ThrowHelper.ThrowInvalidOperationException_InvalidChainedResolver();
 01150                }
 01151            }
 1152
 1153            protected override void OnCollectionModifying()
 01154            {
 01155                _options?.VerifyMutable();
 01156            }
 1157
 1158            protected override void OnCollectionModified()
 01159            {
 1160                // Collection modified by the user: replace the main
 1161                // resolver with the resolver chain as our source of truth.
 01162                _options?._typeInfoResolver = this;
 01163            }
 1164        }
 1165
 1166        [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 1167        [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 1168        private static JsonSerializerOptions GetOrCreateSingleton(
 1169            ref JsonSerializerOptions? location,
 1170            JsonSerializerDefaults defaults)
 01171        {
 01172            var options = new JsonSerializerOptions(defaults)
 01173            {
 01174                // Because we're marking the default instance as read-only,
 01175                // we need to specify a resolver instance for the case where
 01176                // reflection is disabled by default: use one that returns null for all types.
 01177
 01178                TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault
 01179                    ? DefaultJsonTypeInfoResolver.DefaultInstance
 01180                    : JsonTypeInfoResolver.Empty,
 01181
 01182                _isReadOnly = true,
 01183            };
 1184
 01185            return Interlocked.CompareExchange(ref location, options, null) ?? options;
 01186        }
 1187
 1188        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 01189        private string DebuggerDisplay => $"TypeInfoResolver = {(TypeInfoResolver?.ToString() ?? "<null>")}, IsReadOnly 
 1190    }
 1191}

Methods/Properties

CacheContext()
rCreate()
GetTypeInfo(System.Type)
TryGetTypeInfo(System.Type,System.Text.Json.Serialization.Metadata.JsonTypeInfo&)
GetTypeInfo()
TryGetTypeInfo(System.Text.Json.Serialization.Metadata.JsonTypeInfo`1<T>&)
GetTypeInfoInternal(System.Type,System.Boolean,System.Nullable`1<System.Boolean>,System.Boolean,System.Boolean)
TryGetTypeInfoCached(System.Type,System.Text.Json.Serialization.Metadata.JsonTypeInfo&)
GetTypeInfoForRootType(System.Type,System.Boolean)
TryGetPolymorphicTypeInfoForRootType(System.Object,System.Text.Json.Serialization.Metadata.JsonTypeInfo&)
ObjectTypeInfo()
ClearCaches()
.ctor(System.Text.Json.JsonSerializerOptions,System.Int32)
Options()
HashCode()
Count()
GetOrAddTypeInfo(System.Type,System.Boolean)
TryGetTypeInfo(System.Type,System.Text.Json.Serialization.Metadata.JsonTypeInfo&)
Clear()
GetOrAddCacheEntry(System.Type)
CreateCacheEntry(System.Type,System.Text.Json.JsonSerializerOptions/CachingContext)
FallBackToNearestAncestor(System.Type,System.Text.Json.JsonSerializerOptions/CachingContext/CacheEntry)
DetermineNearestAncestor(System.Type,System.Text.Json.JsonSerializerOptions/CachingContext/CacheEntry)
.ctor(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
.ctor(System.Runtime.ExceptionServices.ExceptionDispatchInfo)
GetResult()
.cctor()
GetOrCreate(System.Text.Json.JsonSerializerOptions)
TryGetContext(System.Text.Json.JsonSerializerOptions,System.Int32,System.Int32&,System.Text.Json.JsonSerializerOptions/CachingContext&)
Equals(System.Text.Json.JsonSerializerOptions,System.Text.Json.JsonSerializerOptions)
CompareLists(System.Text.Json.Serialization.ConfigurationList`1<TValue>,System.Text.Json.Serialization.ConfigurationList`1<TValue>)
GetHashCode(System.Text.Json.JsonSerializerOptions)
AddListHashCode(System.HashCode&,System.Text.Json.Serialization.ConfigurationList`1<TValue>)
AddHashCode(System.HashCode&,TValue)
Converters()
GetConverter(System.Type)
GetConverterInternal(System.Type)
GetConverterFromList(System.Type)
ExpandConverterFactory(System.Text.Json.Serialization.JsonConverter,System.Type)
CheckConverterNullabilityIsSameAsPropertyType(System.Text.Json.Serialization.JsonConverter,System.Type)
Default()
Web()
Strict()
.ctor()
.ctor(System.Text.Json.JsonSerializerOptions)
.ctor(System.Text.Json.JsonSerializerDefaults)
TrackOptionsInstance(System.Text.Json.JsonSerializerOptions)
All()
.cctor()
AddContext()
TypeInfoResolver()
TypeInfoResolver(System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver)
TypeInfoResolverChain()
AllowOutOfOrderMetadataProperties()
AllowOutOfOrderMetadataProperties(System.Boolean)
AllowTrailingCommas()
AllowTrailingCommas(System.Boolean)
DefaultBufferSize()
DefaultBufferSize(System.Int32)
Encoder()
Encoder(System.Text.Encodings.Web.JavaScriptEncoder)
DictionaryKeyPolicy()
DictionaryKeyPolicy(System.Text.Json.JsonNamingPolicy)
IgnoreNullValues()
IgnoreNullValues(System.Boolean)
DefaultIgnoreCondition()
DefaultIgnoreCondition(System.Text.Json.Serialization.JsonIgnoreCondition)
NumberHandling()
NumberHandling(System.Text.Json.Serialization.JsonNumberHandling)
PreferredObjectCreationHandling()
PreferredObjectCreationHandling(System.Text.Json.Serialization.JsonObjectCreationHandling)
IgnoreReadOnlyProperties()
IgnoreReadOnlyProperties(System.Boolean)
IgnoreReadOnlyFields()
IgnoreReadOnlyFields(System.Boolean)
IncludeFields()
IncludeFields(System.Boolean)
MaxDepth()
MaxDepth(System.Int32)
EffectiveMaxDepth()
PropertyNamingPolicy()
PropertyNamingPolicy(System.Text.Json.JsonNamingPolicy)
PropertyNameCaseInsensitive()
PropertyNameCaseInsensitive(System.Boolean)
ReadCommentHandling()
ReadCommentHandling(System.Text.Json.JsonCommentHandling)
UnknownTypeHandling()
UnknownTypeHandling(System.Text.Json.Serialization.JsonUnknownTypeHandling)
UnmappedMemberHandling()
UnmappedMemberHandling(System.Text.Json.Serialization.JsonUnmappedMemberHandling)
WriteIndented()
WriteIndented(System.Boolean)
IndentCharacter()
IndentCharacter(System.Char)
IndentSize()
IndentSize(System.Int32)
ReferenceHandler()
ReferenceHandler(System.Text.Json.Serialization.ReferenceHandler)
NewLine()
NewLine(System.String)
RespectNullableAnnotations()
RespectNullableAnnotations(System.Boolean)
RespectRequiredConstructorParameters()
RespectRequiredConstructorParameters(System.Boolean)
AllowDuplicateProperties()
AllowDuplicateProperties(System.Boolean)
CanUseFastPathSerializationLogic()
IsReadOnly()
MakeReadOnly()
MakeReadOnly(System.Boolean)
ConfigureForJsonSerializer()
GetTypeInfoNoCaching(System.Type)
GetDocumentOptions()
GetNodeOptions()
GetReaderOptions()
GetWriterOptions()
VerifyMutable()
.ctor(System.Text.Json.JsonSerializerOptions,System.Collections.Generic.IList`1<System.Text.Json.Serialization.JsonConverter>)
IsReadOnly()
OnCollectionModifying()
.ctor(System.Text.Json.JsonSerializerOptions)
DetachFromOptions()
IsReadOnly()
ValidateAddedValue(System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver)
OnCollectionModifying()
OnCollectionModified()
GetOrCreateSingleton(System.Text.Json.JsonSerializerOptions&,System.Text.Json.JsonSerializerDefaults)
DebuggerDisplay()