File: System\Text\Json\Serialization\JsonSerializerContext.cs
Web Access
Project: src\src\libraries\System.Text.Json\src\System.Text.Json.csproj (System.Text.Json)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Text.Json.Serialization.Metadata;
 
namespace System.Text.Json.Serialization
{
    /// <summary>
    /// Provides metadata about a set of types that is relevant to JSON serialization.
    /// </summary>
    public abstract partial class JsonSerializerContext : IJsonTypeInfoResolver, IBuiltInJsonTypeInfoResolver
    {
        private JsonSerializerOptions? _options;
 
        /// <summary>
        /// Gets the run time specified options of the context. If no options were passed
        /// when instantiating the context, then a new instance is bound and returned.
        /// </summary>
        /// <remarks>
        /// The options instance cannot be mutated once it is bound to the context instance.
        /// </remarks>
        public JsonSerializerOptions Options
        {
            get
            {
                JsonSerializerOptions? options = _options;
 
                if (options is null)
                {
                    options = new JsonSerializerOptions { TypeInfoResolver = this };
                    options.MakeReadOnly();
                    _options = options;
                }
 
                return options;
            }
        }
 
        internal void AssociateWithOptions(JsonSerializerOptions options)
        {
            Debug.Assert(!options.IsReadOnly);
            options.TypeInfoResolver = this;
            options.MakeReadOnly();
            _options = options;
        }
 
        /// <summary>
        /// Indicates whether pre-generated serialization logic for types in the context
        /// is compatible with the run time specified <see cref="JsonSerializerOptions"/>.
        /// </summary>
        bool IBuiltInJsonTypeInfoResolver.IsCompatibleWithOptions(JsonSerializerOptions options)
        {
            Debug.Assert(options != null);
 
            JsonSerializerOptions? generatedSerializerOptions = GeneratedSerializerOptions;
 
            return
                generatedSerializerOptions is not null &&
                // Guard against unsupported features
                options.Converters.Count == 0 &&
                options.Encoder is null &&
                // Disallow custom number handling we'd need to honor when writing.
                // AllowReadingFromString and Strict are fine since there's no action to take when writing.
                !JsonHelpers.RequiresSpecialNumberHandlingOnWrite(options.NumberHandling) &&
                options.ReferenceHandlingStrategy == JsonKnownReferenceHandler.Unspecified &&
#pragma warning disable SYSLIB0020
                !options.IgnoreNullValues && // This property is obsolete.
#pragma warning restore SYSLIB0020
 
                // Ensure options values are consistent with expected defaults.
                options.DefaultIgnoreCondition == generatedSerializerOptions.DefaultIgnoreCondition &&
                options.RespectNullableAnnotations == generatedSerializerOptions.RespectNullableAnnotations &&
                options.IgnoreReadOnlyFields == generatedSerializerOptions.IgnoreReadOnlyFields &&
                options.IgnoreReadOnlyProperties == generatedSerializerOptions.IgnoreReadOnlyProperties &&
                options.IncludeFields == generatedSerializerOptions.IncludeFields &&
                options.PropertyNamingPolicy == generatedSerializerOptions.PropertyNamingPolicy &&
                options.DictionaryKeyPolicy is null;
        }
 
        /// <summary>
        /// The default run time options for the context. Its values are defined at design-time via <see cref="JsonSourceGenerationOptionsAttribute"/>.
        /// </summary>
        protected abstract JsonSerializerOptions? GeneratedSerializerOptions { get; }
 
        /// <summary>
        /// Creates an instance of <see cref="JsonSerializerContext"/> and binds it with the indicated <see cref="JsonSerializerOptions"/>.
        /// </summary>
        /// <param name="options">The run time provided options for the context instance.</param>
        /// <remarks>
        /// If no instance options are passed, then no options are set until the context is bound using <see cref="JsonSerializerOptions.AddContext{TContext}"/>,
        /// or until <see cref="Options"/> is called, where a new options instance is created and bound.
        /// </remarks>
        protected JsonSerializerContext(JsonSerializerOptions? options)
        {
            if (options != null)
            {
                options.VerifyMutable();
                AssociateWithOptions(options);
            }
        }
 
        /// <summary>
        /// Returns a <see cref="JsonTypeInfo"/> instance representing the given type.
        /// </summary>
        /// <param name="type">The type to fetch metadata about.</param>
        /// <returns>The metadata for the specified type, or <see langword="null" /> if the context has no metadata for the type.</returns>
        public abstract JsonTypeInfo? GetTypeInfo(Type type);
 
        JsonTypeInfo? IJsonTypeInfoResolver.GetTypeInfo(Type type, JsonSerializerOptions options)
        {
            if (options != null && options != _options)
            {
                ThrowHelper.ThrowInvalidOperationException_ResolverTypeInfoOptionsNotCompatible();
            }
 
            return GetTypeInfo(type);
        }
    }
}