/// <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)); }
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); }
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)); }