File: System\Text\Json\Serialization\Metadata\JsonTypeInfoOfT.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.ComponentModel;
using System.Diagnostics;
 
namespace System.Text.Json.Serialization.Metadata
{
    /// <summary>
    /// Provides JSON serialization-related metadata about a type.
    /// </summary>
    /// <typeparam name="T">The generic definition of the type.</typeparam>
    public sealed partial class JsonTypeInfo<T> : JsonTypeInfo
    {
        private Action<Utf8JsonWriter, T>? _serialize;
 
        private Func<T>? _typedCreateObject;
 
        internal JsonTypeInfo(JsonConverter converter, JsonSerializerOptions options)
            : base(typeof(T), converter, options)
        {
            EffectiveConverter = converter.CreateCastingConverter<T>();
        }
 
        /// <summary>
        /// A Converter whose declared type always matches that of the current JsonTypeInfo.
        /// It might be the same instance as JsonTypeInfo.Converter or it could be wrapped
        /// in a CastingConverter in cases where a polymorphic converter is being used.
        /// </summary>
        internal JsonConverter<T> EffectiveConverter { get; }
 
        /// <summary>
        /// Gets or sets a parameterless factory to be used on deserialization.
        /// </summary>
        /// <exception cref="InvalidOperationException">
        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
        ///
        /// -or-
        ///
        /// A parameterless factory is not supported for the current metadata <see cref="JsonTypeInfo.Kind"/>.
        /// </exception>
        /// <remarks>
        /// If set to <see langword="null" />, any attempt to deserialize instances of the given type will fail at runtime.
        ///
        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext"/>,
        /// types with a single default constructor or default constructors annotated with <see cref="JsonConstructorAttribute"/>
        /// will be mapped to this delegate.
        /// </remarks>
        public new Func<T>? CreateObject
        {
            get => _typedCreateObject;
            set
            {
                SetCreateObject(value);
            }
        }
 
        private protected override void SetCreateObject(Delegate? createObject)
        {
            Debug.Assert(createObject is null or Func<object> or Func<T>);
 
            VerifyMutable();
 
            if (Kind == JsonTypeInfoKind.None)
            {
                Debug.Assert(_createObject == null);
                Debug.Assert(_typedCreateObject == null);
                ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
            }
 
            if (!Converter.SupportsCreateObjectDelegate)
            {
                Debug.Assert(_createObject is null);
                Debug.Assert(_typedCreateObject == null);
                ThrowHelper.ThrowInvalidOperationException_CreateObjectConverterNotCompatible(Type);
            }
 
            Func<object>? untypedCreateObject;
            Func<T>? typedCreateObject;
 
            if (createObject is null)
            {
                untypedCreateObject = null;
                typedCreateObject = null;
            }
            else if (createObject is Func<T> typedDelegate)
            {
                typedCreateObject = typedDelegate;
                untypedCreateObject = createObject is Func<object> untypedDelegate ? untypedDelegate : () => typedDelegate()!;
            }
            else
            {
                Debug.Assert(createObject is Func<object>);
                untypedCreateObject = (Func<object>)createObject;
                typedCreateObject = () => (T)untypedCreateObject();
            }
 
            _createObject = untypedCreateObject;
            _typedCreateObject = typedCreateObject;
 
            // Clear any data related to the previously specified ctor
            ConstructorAttributeProviderFactory = null;
            ConstructorAttributeProvider = null;
 
            if (CreateObjectWithArgs is not null)
            {
                _parameterInfoValuesIndex = null;
                CreateObjectWithArgs = null;
                ParameterCount = 0;
 
                foreach (JsonPropertyInfo propertyInfo in PropertyList)
                {
                    propertyInfo.AssociatedParameter = null;
                }
            }
        }
 
        /// <summary>
        /// Serializes an instance of <typeparamref name="T"/> using
        /// <see cref="JsonSourceGenerationOptionsAttribute"/> values specified at design time.
        /// </summary>
        /// <remarks>The writer is not flushed after writing.</remarks>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public Action<Utf8JsonWriter, T>? SerializeHandler
        {
            get
            {
                return _serialize;
            }
            internal set
            {
                Debug.Assert(!IsReadOnly, "We should not mutate read-only JsonTypeInfo");
                _serialize = value;
                HasSerializeHandler = value != null;
            }
        }
 
        private protected override JsonPropertyInfo CreatePropertyInfoForTypeInfo()
        {
            return new JsonPropertyInfo<T>(
                declaringType: typeof(T),
                declaringTypeInfo: this,
                Options)
            {
                JsonTypeInfo = this,
                IsForTypeInfo = true,
            };
        }
 
        private protected override JsonPropertyInfo CreateJsonPropertyInfo(JsonTypeInfo declaringTypeInfo, Type? declaringType, JsonSerializerOptions options)
        {
            return new JsonPropertyInfo<T>(declaringType ?? declaringTypeInfo.Type, declaringTypeInfo, options)
            {
                JsonTypeInfo = this
            };
        }
    }
}