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