internal JsonConverter DetermineConverter(Type?parentClassType, Type runtimePropertyType, MemberInfo?memberInfo) { JsonConverter converter = null !; // Priority 1: attempt to get converter from JsonConverterAttribute on property. if (memberInfo != null) { Debug.Assert(parentClassType != null); JsonConverterAttribute?converterAttribute = (JsonConverterAttribute?) GetAttributeThatCanHaveMultiple(parentClassType !, typeof(JsonConverterAttribute), memberInfo); if (converterAttribute != null) { converter = GetConverterFromAttribute(converterAttribute, typeToConvert: runtimePropertyType, classTypeAttributeIsOn: parentClassType !, memberInfo); } } if (converter == null) { converter = GetConverter(runtimePropertyType); Debug.Assert(converter != null); } if (converter is JsonConverterFactory factory) { converter = factory.GetConverterInternal(runtimePropertyType, this); // A factory cannot return null; GetConverterInternal checked for that. Debug.Assert(converter != null); } // User indicated that non-nullable-struct-handling converter should handle a nullable struct type. // The serializer would have picked that converter up by default and wrapped it in NullableConverter<T>; // throw so that user can modify or remove their unnecessary CanConvert method override. // // We also throw to avoid passing an invalid argument to setters for nullable struct properties, // which would cause an InvalidProgramException when the generated IL is invoked. // This is not an issue of the converter is wrapped in NullableConverter<T>. if (runtimePropertyType.CanBeNull() && !converter.TypeToConvert.CanBeNull()) { ThrowHelper.ThrowInvalidOperationException_ConverterCanConvertNullableRedundant(runtimePropertyType, converter); } return(converter); }