private JSchema GenerateInternal(Type type, Required?valueRequired, JsonProperty memberProperty, JsonContainerContract container, JSchemaGenerationProvider currentGenerationProvider)
        {
            ValidationUtils.ArgumentNotNull(type, nameof(type));

            Type nonNullableType = ReflectionUtils.IsNullableType(type) ? Nullable.GetUnderlyingType(type) : type;

            Uri explicitId = GetTypeId(nonNullableType, true);

            JsonContract contract = _generator.ContractResolver.ResolveContract(type);

            Required resolvedRequired = valueRequired ?? _generator.DefaultRequired;

            TypeSchemaKey key = CreateKey(resolvedRequired, memberProperty, contract);

            if (ShouldReferenceType(contract))
            {
                TypeSchema typeSchema = GetCachedSchema(key);
                if (typeSchema != null)
                {
                    return(typeSchema.Schema);
                }
            }

            JSchema schema = null;

            JSchemaGenerationProvider provider = ResolveTypeProvider(nonNullableType, memberProperty);

            if (provider != null && provider != currentGenerationProvider)
            {
                JSchemaTypeGenerationContext context = new JSchemaTypeGenerationContext(type, resolvedRequired, memberProperty, container, this);
                context.GenerationProvider = provider;

                schema = provider.GetSchema(context);

                if (schema == null)
                {
                    throw new JSchemaException("Could not get schema for type '{0}' from provider '{1}'.".FormatWith(CultureInfo.InvariantCulture, type.FullName, provider.GetType().FullName));
                }
            }

            if (_generator._generationProviders != null)
            {
                JSchemaTypeGenerationContext context = new JSchemaTypeGenerationContext(type, resolvedRequired, memberProperty, container, this);

                foreach (JSchemaGenerationProvider generationProvider in _generator._generationProviders)
                {
                    if (generationProvider != currentGenerationProvider && generationProvider.CanGenerateSchema(context))
                    {
                        context.GenerationProvider = generationProvider;

                        schema = generationProvider.GetSchema(context);
                        break;
                    }
                }
            }

            if (schema != null)
            {
                // check to see whether the generation provide had already generated the type recursively
                // and reuse that cached schema rather than duplicate
                TypeSchema typeSchema = GetCachedSchema(key);

                if (typeSchema != null)
                {
                    schema = typeSchema.Schema;
                }
                else
                {
                    if (ShouldReferenceType(contract))
                    {
                        _typeSchemas.Add(new TypeSchema(key, schema));
                    }
                }
            }
            else
            {
                schema = new JSchema();
                if (explicitId != null)
                {
                    schema.Id = explicitId;
                }

                if (ShouldReferenceType(contract))
                {
                    _typeSchemas.Add(new TypeSchema(key, schema));
                }

                PopulateSchema(schema, contract, memberProperty, resolvedRequired);
            }

            return(schema);
        }
        private JSchema GenerateInternal(Type type, Required?valueRequired, JsonProperty memberProperty, JsonContainerContract container)
        {
            ValidationUtils.ArgumentNotNull(type, "type");

            Type nonNullableType = ReflectionUtils.IsNullableType(type) ? Nullable.GetUnderlyingType(type) : type;

            Uri explicitId = GetTypeId(nonNullableType, true);

            JsonContract contract = _generator.ContractResolver.ResolveContract(type);

            Required resolvedRequired = valueRequired ?? _generator.DefaultRequired;

            TypeSchemaKey key = CreateKey(resolvedRequired, memberProperty, contract);

            if (ShouldReferenceType(contract))
            {
                TypeSchema typeSchema = _typeSchemas.SingleOrDefault(s => s.Key.Equals(key));
                if (typeSchema != null)
                {
                    return(typeSchema.Schema);
                }
            }

            JSchema schema = null;

            JSchemaGenerationProvider provider = ResolveTypeProvider(nonNullableType, memberProperty);

            if (provider != null)
            {
                JSchemaTypeGenerationContext context = new JSchemaTypeGenerationContext(type, resolvedRequired, memberProperty, container, _generator);

                schema = provider.GetSchema(context);

                if (schema == null)
                {
                    throw new JSchemaException("Could not get schema for type '{0}' from provider '{1}'.".FormatWith(CultureInfo.InvariantCulture, type.FullName, provider.GetType().FullName));
                }
            }

            if (_generator._generationProviders != null)
            {
                JSchemaTypeGenerationContext context = new JSchemaTypeGenerationContext(type, resolvedRequired, memberProperty, container, _generator);

                foreach (JSchemaGenerationProvider generationProvider in _generator._generationProviders)
                {
                    schema = generationProvider.GetSchema(context);
                }
            }

            if (schema != null)
            {
                if (ShouldReferenceType(contract))
                {
                    _typeSchemas.Add(new TypeSchema(key, schema));
                }
            }
            else
            {
                schema = new JSchema();
                if (explicitId != null)
                {
                    schema.Id = explicitId;
                }

                if (ShouldReferenceType(contract))
                {
                    _typeSchemas.Add(new TypeSchema(key, schema));
                }

                PopulateSchema(schema, contract, memberProperty, resolvedRequired);
            }

            return(schema);
        }