| File: System\Text\Json\Serialization\Converters\Object\ObjectConverterFactory.cs | Web Access |
| Project: src\runtime\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.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json.Reflection; using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization.Converters { /// <summary> /// Converter factory for all object-based types (non-enumerable and non-primitive). /// </summary> [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)] internal sealed class ObjectConverterFactory : JsonConverterFactory { // Need to toggle this behavior when generating converters for F# struct records. private readonly bool _useDefaultConstructorInUnannotatedStructs; [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] public ObjectConverterFactory(bool useDefaultConstructorInUnannotatedStructs = true) { _useDefaultConstructorInUnannotatedStructs = useDefaultConstructorInUnannotatedStructs; } public override bool CanConvert(Type typeToConvert) { // This is the last built-in factory converter, so if the IEnumerableConverterFactory doesn't // support it, then it is not IEnumerable. Debug.Assert(!typeof(IEnumerable).IsAssignableFrom(typeToConvert)); return true; } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "The ctor is marked RequiresUnreferencedCode.")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern", Justification = "The ctor is marked RequiresUnreferencedCode.")] public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { JsonConverter converter; Type converterType; bool useDefaultConstructorInUnannotatedStructs = _useDefaultConstructorInUnannotatedStructs && !typeToConvert.IsKeyValuePair(); if (!typeToConvert.TryGetDeserializationConstructor(useDefaultConstructorInUnannotatedStructs, out ConstructorInfo? constructor)) { ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute<JsonConstructorAttribute>(typeToConvert); } ParameterInfo[]? parameters = constructor?.GetParameters(); if (constructor == null || typeToConvert.IsAbstract || parameters!.Length == 0) { converterType = typeof(ObjectDefaultConverter<>).MakeGenericType(typeToConvert); } else { int parameterCount = parameters.Length; foreach (ParameterInfo parameter in parameters) { // Skip out parameters — they don't receive values from JSON // and may reference unsupported types (e.g. Task). if (parameter.IsOut) { continue; } // Every argument must be of supported type. // For byref parameters (in/ref), validate the underlying element type. Type parameterType = parameter.ParameterType; if (parameterType.IsByRef) { parameterType = parameterType.GetElementType()!; } JsonTypeInfo.ValidateType(parameterType); } if (parameterCount <= JsonConstants.UnboxedParameterCountThreshold) { Type placeHolderType = JsonTypeInfo.ObjectType; Type[] typeArguments = new Type[JsonConstants.UnboxedParameterCountThreshold + 1]; typeArguments[0] = typeToConvert; for (int i = 0; i < JsonConstants.UnboxedParameterCountThreshold; i++) { if (i < parameterCount) { // out parameters use placeholder type — they aren't deserialized // and may reference types that can't be used as generic arguments. if (parameters[i].IsOut) { typeArguments[i + 1] = placeHolderType; } else { // For byref parameters (in/ref), use the underlying element type // since byref types cannot be used as generic type arguments. Type parameterType = parameters[i].ParameterType; if (parameterType.IsByRef) { parameterType = parameterType.GetElementType()!; } typeArguments[i + 1] = parameterType; } } else { // Use placeholder arguments if there are less args than the threshold. typeArguments[i + 1] = placeHolderType; } } converterType = typeof(SmallObjectWithParameterizedConstructorConverter<,,,,>).MakeGenericType(typeArguments); } else { converterType = typeof(LargeObjectWithParameterizedConstructorConverterWithReflection<>).MakeGenericType(typeToConvert); } } converter = (JsonConverter)Activator.CreateInstance( converterType, BindingFlags.Instance | BindingFlags.Public, binder: null, args: null, culture: null)!; converter.ConstructorInfo = constructor!; return converter; } } }