/// <summary>
        /// Create a <see cref="JsonPropertyInfo"/> for a given Type.
        /// </summary>
        internal JsonPropertyInfo CreateRootProperty(JsonSerializerOptions options)
        {
            JsonConverter converter = options.DetermineConverterForProperty(Type, Type, propertyInfo: null);

            return(CreateProperty(
                       declaredPropertyType: Type,
                       runtimePropertyType: Type,
                       propertyInfo: null,
                       parentClassType: typeof(object), // a dummy value (not used)
                       ElementType,
                       Nullable.GetUnderlyingType(Type),
                       converter,
                       ClassType,
                       options));
        }
示例#2
0
        internal static JsonPropertyInfo CreateProperty(
            Type declaredPropertyType,
            Type runtimePropertyType,
            Type implementedPropertyType,
            PropertyInfo propertyInfo,
            Type parentClassType,
            JsonSerializerOptions options)
        {
            bool hasIgnoreAttribute = (JsonPropertyInfo.GetAttribute <JsonIgnoreAttribute>(propertyInfo) != null);

            if (hasIgnoreAttribute)
            {
                return(JsonPropertyInfo.CreateIgnoredPropertyPlaceholder(propertyInfo, options));
            }

            Type collectionElementType = null;

            switch (GetClassType(runtimePropertyType, options))
            {
            case ClassType.Enumerable:
            case ClassType.Dictionary:
            case ClassType.IDictionaryConstructible:
            case ClassType.Unknown:
                collectionElementType = GetElementType(runtimePropertyType, parentClassType, propertyInfo, options);
                break;
            }

            JsonConverter converter;

            // Create the JsonPropertyInfo<TType, TProperty>
            Type propertyInfoClassType;

            if (runtimePropertyType.IsGenericType && runtimePropertyType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                // For Nullable, use the underlying type.
                Type underlyingPropertyType = Nullable.GetUnderlyingType(runtimePropertyType);
                propertyInfoClassType = typeof(JsonPropertyInfoNullable <,>).MakeGenericType(parentClassType, underlyingPropertyType);
                converter             = options.DetermineConverterForProperty(parentClassType, underlyingPropertyType, propertyInfo);
            }
            else
            {
                converter = options.DetermineConverterForProperty(parentClassType, runtimePropertyType, propertyInfo);
                Type typeToConvert = converter?.TypeToConvert;
                if (typeToConvert == null)
                {
                    if (IsNativelySupportedCollection(declaredPropertyType))
                    {
                        typeToConvert = implementedPropertyType;
                    }
                    else
                    {
                        typeToConvert = declaredPropertyType;
                    }
                }

                // For the covariant case, create JsonPropertyInfoNotNullable. The generic constraints are "where TConverter : TDeclaredProperty".
                if (runtimePropertyType.IsAssignableFrom(typeToConvert))
                {
                    propertyInfoClassType = typeof(JsonPropertyInfoNotNullable <, , ,>).MakeGenericType(
                        parentClassType,
                        declaredPropertyType,
                        runtimePropertyType,
                        typeToConvert);
                }
                else
                {
                    Debug.Assert(typeToConvert.IsAssignableFrom(runtimePropertyType));

                    // For the contravariant case, create JsonPropertyInfoNotNullableContravariant. The generic constraints are "where TDeclaredProperty : TConverter".
                    propertyInfoClassType = typeof(JsonPropertyInfoNotNullableContravariant <, , ,>).MakeGenericType(
                        parentClassType,
                        declaredPropertyType,
                        runtimePropertyType,
                        typeToConvert);
                }
            }

            JsonPropertyInfo jsonInfo = (JsonPropertyInfo)Activator.CreateInstance(
                propertyInfoClassType,
                BindingFlags.Instance | BindingFlags.Public,
                binder: null,
                args: null,
                culture: null);

            jsonInfo.Initialize(parentClassType, declaredPropertyType, runtimePropertyType, implementedPropertyType, propertyInfo, collectionElementType, converter, options);

            return(jsonInfo);
        }
示例#3
0
        public static Type GetImplementedCollectionType(
            Type parentClassType,
            Type queryType,
            PropertyInfo propertyInfo,
            out JsonConverter converter,
            JsonSerializerOptions options)
        {
            Debug.Assert(queryType != null);

            if (!(typeof(IEnumerable).IsAssignableFrom(queryType)) ||
                queryType == typeof(string) ||
                queryType.IsInterface ||
                queryType.IsArray ||
                IsNativelySupportedCollection(queryType))
            {
                converter = null;
                return(queryType);
            }

            // If a converter was provided, we should not detect implemented types and instead use the converter later.
            converter = options.DetermineConverterForProperty(parentClassType, queryType, propertyInfo);
            if (converter != null)
            {
                return(queryType);
            }

            Type baseType = queryType.GetTypeInfo().BaseType;

            // Check if the base type is a supported concrete collection.
            if (IsNativelySupportedCollection(baseType))
            {
                return(baseType);
            }

            // Try generic interfaces with add methods.
            foreach (Type candidate in s_genericInterfacesWithAddMethods)
            {
                Type derivedGeneric = ExtractGenericInterface(queryType, candidate);
                if (derivedGeneric != null)
                {
                    return(derivedGeneric);
                }
            }

            // Try non-generic interfaces with add methods.
            foreach (Type candidate in s_nonGenericInterfacesWithAddMethods)
            {
                if (candidate.IsAssignableFrom(queryType))
                {
                    return(candidate);
                }
            }

            // Try generic interfaces without add methods
            foreach (Type candidate in s_genericInterfacesWithoutAddMethods)
            {
                Type derivedGeneric = ExtractGenericInterface(queryType, candidate);
                if (derivedGeneric != null)
                {
                    return(derivedGeneric);
                }
            }

            return(typeof(IEnumerable));
        }