Merge branch 'master' of https://github.com/steveharter/dotnet_corefx into DictionaryOfT
authorSteve Harter <steveharter@users.noreply.github.com>
Mon, 21 Oct 2019 22:55:44 +0000 (17:55 -0500)
committerSteve Harter <steveharter@users.noreply.github.com>
Mon, 21 Oct 2019 22:55:44 +0000 (17:55 -0500)
Commit migrated from https://github.com/dotnet/corefx/commit/d52aae926802668d0296fa346bcbe50b1b3a3cab

12 files changed:
1  2 
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultImmutableDictionaryConverter.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultImmutableEnumerableConverter.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoCommon.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullableContravariant.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleDictionary.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleValue.cs

@@@ -63,7 -65,8 +65,8 @@@ namespace System.Text.Json.Serializatio
  
              string delegateKey = DefaultImmutableEnumerableConverter.GetDelegateKey(immutableCollectionType, elementType, out _, out _);
  
-             JsonPropertyInfo propertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementType, options);
 -            JsonPropertyInfo propertyInfo = elementClassInfo.PolicyProperty ?? elementClassInfo.CreateRootObject(options);
++            JsonPropertyInfo propertyInfo = elementClassInfo.PolicyProperty ?? elementClassInfo.CreateRootProperty(options);
+             Debug.Assert(propertyInfo != null);
              return propertyInfo.CreateImmutableDictionaryInstance(ref state, immutableCollectionType, delegateKey, sourceDictionary, options);
          }
      }
@@@ -109,7 -141,8 +141,8 @@@ namespace System.Text.Json.Serializatio
  
              string delegateKey = GetDelegateKey(immutableCollectionType, elementType, out _, out _);
  
-             JsonPropertyInfo propertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementType, options);
 -            JsonPropertyInfo propertyInfo = elementClassInfo.PolicyProperty ?? elementClassInfo.CreateRootObject(options);
++            JsonPropertyInfo propertyInfo = elementClassInfo.PolicyProperty ?? elementClassInfo.CreateRootProperty(options);
+             Debug.Assert(propertyInfo != null);
              return propertyInfo.CreateImmutableCollectionInstance(ref state, immutableCollectionType, delegateKey, sourceList, options);
          }
      }
@@@ -197,33 -116,60 +116,89 @@@ namespace System.Text.Jso
              return jsonPropertyInfo;
          }
  
 -        internal JsonPropertyInfo CreateRootObject(JsonSerializerOptions options)
 +        /// <summary>
 +        /// Create a <see cref="JsonPropertyInfo"/> for a given Type.
++        /// A policy property is not a real property on a type; instead it leverages the existing converter
++        /// logic and generic support to avoid boxing. It is used with values types, elements from collections and
++        /// dictionaries, and collections themselves. Typically it would represent a CLR type such as System.String.
++        /// </summary>
++        internal static JsonPropertyInfo CreatePolicyProperty(
++            Type declaredPropertyType,
++            Type runtimePropertyType,
++            Type elementType,
++            JsonConverter converter,
++            ClassType classType,
++            JsonSerializerOptions options)
++        {
++            return CreateProperty(
++                declaredPropertyType: declaredPropertyType,
++                runtimePropertyType: runtimePropertyType,
++                propertyInfo: null, // Not a real property so this is null.
++                parentClassType: typeof(object), // a dummy value (not used)
++                collectionElementType : elementType,
++                Nullable.GetUnderlyingType(runtimePropertyType),
++                converter : converter,
++                classType : classType,
++                options);
++        }
++
++        /// <summary>
++        /// Create a <see cref="JsonPropertyInfo"/> for a given Type.
 +        /// </summary>
-         internal static JsonPropertyInfo CreateRootProperty(Type type, JsonSerializerOptions options)
++        internal JsonPropertyInfo CreateRootProperty(JsonSerializerOptions options)
          {
+             JsonConverter converter = options.DetermineConverterForProperty(Type, Type, propertyInfo: null);
              return CreateProperty(
-                 declaredPropertyType: type,
-                 runtimePropertyType: type,
-                 implementedPropertyType: type,
+                 declaredPropertyType: Type,
+                 runtimePropertyType: Type,
                  propertyInfo: null,
 -                parentClassType: Type,
 +                parentClassType: typeof(object), // a dummy value (not used)
-                 converter: null,
-                 options: options);
+                 ElementType,
+                 Nullable.GetUnderlyingType(Type),
+                 converter,
+                 ClassType,
+                 options);
          }
  
-         internal JsonPropertyInfo CreatePolymorphicProperty(JsonPropertyInfo property, Type runtimePropertyType, JsonSerializerOptions options)
+         internal JsonPropertyInfo GetOrAddPolymorphicProperty(JsonPropertyInfo property, Type runtimePropertyType, JsonSerializerOptions options)
          {
-             JsonPropertyInfo runtimeProperty = CreateProperty(
-                 property.DeclaredPropertyType, runtimePropertyType,
-                 property.ImplementedPropertyType,
-                 property.PropertyInfo,
-                 parentClassType: Type,
-                 converter: null,
-                 options: options);
-             property.CopyRuntimeSettingsTo(runtimeProperty);
-             return runtimeProperty;
+             static JsonPropertyInfo CreateRuntimeProperty((JsonPropertyInfo property, Type runtimePropertyType) key, (JsonSerializerOptions options, Type classType) arg)
+             {
+                 ClassType classType = GetClassType(
+                     key.runtimePropertyType,
+                     arg.classType,
+                     key.property.PropertyInfo,
+                     out _,
+                     out Type elementType,
+                     out Type nullableType,
+                     out _,
+                     out JsonConverter converter,
+                     checkForAddMethod: false,
+                     arg.options);
+                 JsonPropertyInfo runtimeProperty = CreateProperty(
+                     key.property.DeclaredPropertyType,
+                     key.runtimePropertyType,
+                     key.property.PropertyInfo,
+                     parentClassType: arg.classType,
+                     collectionElementType: elementType,
+                     nullableType,
+                     converter,
+                     classType,
+                     options: arg.options);
+                 key.property.CopyRuntimeSettingsTo(runtimeProperty);
+                 return runtimeProperty;
+             }
+             ConcurrentDictionary<(JsonPropertyInfo, Type), JsonPropertyInfo> cache =
+                 LazyInitializer.EnsureInitialized(ref RuntimePropertyCache, () => new ConcurrentDictionary<(JsonPropertyInfo, Type), JsonPropertyInfo>());
+ #if BUILDING_INBOX_LIBRARY
+             return cache.GetOrAdd((property, runtimePropertyType), (key, arg) => CreateRuntimeProperty(key, arg), (options, Type));
+ #else
+             return cache.GetOrAdd((property, runtimePropertyType), key => CreateRuntimeProperty(key, (options, Type)));
+ #endif
          }
      }
  }
@@@ -188,48 -201,65 +201,25 @@@ namespace System.Text.Jso
                  case ClassType.Enumerable:
                  case ClassType.Dictionary:
                      {
--                        // Add a single property that maps to the class type so we can have policies applied.
-                         AddPolicyProperty(type, options);
-                         Type objectType;
-                         if (IsNativelySupportedCollection(type))
-                         {
-                             // Use the type from the property policy to get any late-bound concrete types (from an interface like IDictionary).
-                             objectType = PolicyProperty.RuntimePropertyType;
-                         }
-                         else
-                         {
-                             // We need to create the declared instance for types implementing natively supported collections.
-                             objectType = PolicyProperty.DeclaredPropertyType;
-                         }
-                         CreateObject = options.MemberAccessorStrategy.CreateConstructor(objectType);
-                         ElementType = GetElementType(type, parentType: null, memberInfo: null, options: options);
+                         ElementType = elementType;
+                         AddItemToObject = addMethod;
 -
 -                        // A policy property is not a real property on a type; instead it leverages the existing converter
 -                        // logic and generic support to avoid boxing. It is used with values types, elements from collections and
 -                        // dictionaries, and collections themselves. Typically it would represent a CLR type such as System.String.
 -                        PolicyProperty = CreateProperty(
 -                            declaredPropertyType: type,
 -                            runtimePropertyType: runtimeType,
 -                            propertyInfo: null, // Not a real property so this is null.
 -                            parentClassType: typeof(object),
 -                            collectionElementType: elementType,
 -                            nullableUnderlyingType,
 -                            converter: null,
 -                            ClassType,
 -                            options);
 -
++                        PolicyProperty = CreatePolicyProperty(type, runtimeType, elementType, converter: null, ClassType, options);
+                         CreateObject = options.MemberAccessorStrategy.CreateConstructor(PolicyProperty.RuntimePropertyType);
                      }
                      break;
-                 case ClassType.IDictionaryConstructible:
+                 case ClassType.Value:
                      {
-                         // Add a single property that maps to the class type so we can have policies applied.
-                         AddPolicyProperty(type, options);
-                         ElementType = GetElementType(type, parentType: null, memberInfo: null, options: options);
-                         CreateConcreteDictionary = options.MemberAccessorStrategy.CreateConstructor(
-                            typeof(Dictionary<,>).MakeGenericType(typeof(string), ElementType));
-                         CreateObject = options.MemberAccessorStrategy.CreateConstructor(PolicyProperty.DeclaredPropertyType);
+                         CreateObject = options.MemberAccessorStrategy.CreateConstructor(type);
 -
 -                        // Add a single property that maps to the class type so we can have policies applied.
 -                        //AddPolicyPropertyForValue(type, options);
 -                        PolicyProperty = CreateProperty(
 -                            declaredPropertyType: type,
 -                            runtimePropertyType: runtimeType,
 -                            propertyInfo: null, // Not a real property so this is null.
 -                            parentClassType: typeof(object),
 -                            collectionElementType: null,
 -                            nullableUnderlyingType,
 -                            converter,
 -                            ClassType,
 -                            options);
++                        PolicyProperty = CreatePolicyProperty(type, runtimeType, elementType: null, converter, ClassType, options);
                      }
                      break;
-                 case ClassType.Value:
-                     // Add a single property that maps to the class type so we can have policies applied.
-                     AddPolicyProperty(type, options);
-                     break;
                  case ClassType.Unknown:
-                     // Add a single property that maps to the class type so we can have policies applied.
-                     AddPolicyProperty(type, options);
-                     PropertyCache = new Dictionary<string, JsonPropertyInfo>();
-                     PropertyCacheArray = Array.Empty<JsonPropertyInfo>();
+                     {
+                         CreateObject = options.MemberAccessorStrategy.CreateConstructor(type);
 -
 -                        // Add a single property that maps to the class type so we can have policies applied.
 -                        //AddPolicyPropertyForValue(type, options);
 -                        PolicyProperty = CreateProperty(
 -                            declaredPropertyType: type,
 -                            runtimePropertyType: runtimeType,
 -                            propertyInfo: null, // Not a real property so this is null.
 -                            parentClassType: typeof(object),
 -                            collectionElementType: null,
 -                            nullableUnderlyingType,
 -                            converter,
 -                            ClassType,
 -                            options);
 -
++                        PolicyProperty = CreatePolicyProperty(type, runtimeType, elementType: null, converter, ClassType, options);
+                         PropertyCache = new Dictionary<string, JsonPropertyInfo>();
+                         PropertyCacheArray = Array.Empty<JsonPropertyInfo>();
+                     }
                      break;
                  default:
                      Debug.Fail($"Unexpected class type: {ClassType}");
@@@ -28,9 -24,8 +24,10 @@@ namespace System.Text.Jso
          private JsonClassInfo _runtimeClassInfo;
          private JsonClassInfo _declaredTypeClassInfo;
  
 +        private JsonPropertyInfo _dictionaryValuePropertyPolicy;
 +
          public bool CanBeNull { get; private set; }
+         public bool IsImmutableArray { get; private set; }
  
          public ClassType ClassType;
  
          }
  
          /// <summary>
-                     Debug.Assert(ClassType == ClassType.Dictionary || ClassType == ClassType.IDictionaryConstructible);
-                     Type dictionaryValueType = ElementType;
-                     Debug.Assert(ElementType != null);
-                     _dictionaryValuePropertyPolicy = JsonClassInfo.CreateRootProperty(dictionaryValueType, Options);
 +        /// Return the JsonPropertyInfo for the TValue in IDictionary{string, TValue} when deserializing.
++        /// This only needs to contain the raw TValue and does not need converter, etc applied since it
++        /// is only used for "casting" reasons.
 +        /// </summary>
 +        /// <remarks>
 +        /// This should not be called during warm-up (initial creation of JsonPropertyInfos) to avoid recursive behavior
 +        /// which could result in a StackOverflowException.
 +        /// </remarks>
 +        public JsonPropertyInfo DictionaryValuePropertyPolicy
 +        {
 +            get
 +            {
++                Debug.Assert(ClassType == ClassType.Dictionary);
++
 +                if (_dictionaryValuePropertyPolicy == null)
 +                {
++                    //if ((_dictionaryValuePropertyPolicy = ElementClassInfo.PolicyProperty) == null)
++                    {
++                        Type dictionaryValueType = ElementType;
++                        Debug.Assert(dictionaryValueType != null);
++
++                        _dictionaryValuePropertyPolicy = JsonClassInfo.CreatePolicyProperty(
++                            declaredPropertyType : dictionaryValueType,
++                            runtimePropertyType : dictionaryValueType,
++                            elementType : null,
++                            converter: null,
++                            ClassType.Dictionary,
++                            Options);
++                    }
 +                }
 +
 +                return _dictionaryValuePropertyPolicy;
 +            }
 +        }
 +
 +        /// <summary>
          /// Return the JsonClassInfo for the element type, or null if the property is not an enumerable or dictionary.
          /// </summary>
          /// <remarks>
              {
                  if (_elementClassInfo == null && ElementType != null)
                  {
--                    Debug.Assert(ClassType == ClassType.Enumerable ||
-                         ClassType == ClassType.Dictionary ||
-                         ClassType == ClassType.IDictionaryConstructible);
 -                        ClassType == ClassType.Dictionary);
++                    Debug.Assert(ClassType == ClassType.Enumerable || ClassType == ClassType.Dictionary);
  
                      _elementClassInfo = Options.GetOrAddClass(ElementType);
                  }
              return (TAttribute)propertyInfo?.GetCustomAttribute(typeof(TAttribute), inherit: false);
          }
  
-         public abstract Type GetConcreteType(Type type);
          public abstract Type GetDictionaryConcreteType();
  
-             Debug.Assert(ClassType == ClassType.Dictionary ||
-                 ClassType == ClassType.IDictionaryConstructible);
 +        public void GetDictionaryKeyAndValue(ref WriteStackFrame writeStackFrame, out string key, out object value)
 +        {
++            Debug.Assert(ClassType == ClassType.Dictionary);
 +
 +            if (writeStackFrame.CollectionEnumerator is IDictionaryEnumerator iDictionaryEnumerator)
 +            {
 +                // Since IDictionaryEnumerator is not based on generics we can obtain the value directly.
 +                key = (string)iDictionaryEnumerator.Key;
 +                value = iDictionaryEnumerator.Value;
 +            }
 +            else
 +            {
 +                // Forward to the generic dictionary.
 +                DictionaryValuePropertyPolicy.GetDictionaryKeyAndValueFromGenericDictionary(ref writeStackFrame, out key, out value);
 +            }
 +        }
 +
 +        public abstract void GetDictionaryKeyAndValueFromGenericDictionary(ref WriteStackFrame writeStackFrame, out string key, out object value);
 +
          public virtual void GetPolicies()
          {
              DetermineSerializationCapabilities();
@@@ -97,187 -105,102 +105,102 @@@ namespace System.Text.Jso
              }
          }
  
-         public override IList CreateConverterList()
-         {
-             return new List<TDeclaredProperty>();
-         }
+         private JsonPropertyInfo _elementPropertyInfo;
  
-         public override Type GetConcreteType(Type parentType)
+         private void SetPropertyInfoForObjectElement()
          {
-             if (JsonClassInfo.IsDeserializedByAssigningFromList(parentType))
-             {
-                 return typeof(List<TDeclaredProperty>);
-             }
-             else if (JsonClassInfo.IsSetInterface(parentType))
+             if (_elementPropertyInfo == null && ElementClassInfo.PolicyProperty == null)
              {
-                 return typeof(HashSet<TDeclaredProperty>);
 -                _elementPropertyInfo = ElementClassInfo.CreateRootObject(Options);
++                _elementPropertyInfo = ElementClassInfo.CreateRootProperty(Options);
              }
-             return parentType;
          }
  
-         public override IEnumerable CreateDerivedEnumerableInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IList sourceList)
+         public override bool TryCreateEnumerableAddMethod(object target, out object addMethodDelegate)
          {
-             // Implementing types that don't have default constructors are not supported for deserialization.
-             if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
-             {
-                 throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
-                     collectionPropertyInfo.DeclaredPropertyType,
-                     collectionPropertyInfo.ParentClassType,
-                     collectionPropertyInfo.PropertyInfo);
-             }
+             SetPropertyInfoForObjectElement();
+             Debug.Assert((_elementPropertyInfo ?? ElementClassInfo.PolicyProperty) != null);
  
-             object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();
+             addMethodDelegate = (_elementPropertyInfo ?? ElementClassInfo.PolicyProperty).CreateEnumerableAddMethod(RuntimeClassInfo.AddItemToObject, target);
+             return addMethodDelegate != null;
+         }
  
-             if (instance is IList instanceOfIList)
-             {
-                 if (!instanceOfIList.IsReadOnly)
-                 {
-                     foreach (object item in sourceList)
-                     {
-                         instanceOfIList.Add(item);
-                     }
-                     return instanceOfIList;
-                 }
-             }
-             else if (instance is ICollection<TDeclaredProperty> instanceOfICollection)
-             {
-                 if (!instanceOfICollection.IsReadOnly)
-                 {
-                     foreach (TDeclaredProperty item in sourceList)
-                     {
-                         instanceOfICollection.Add(item);
-                     }
-                     return instanceOfICollection;
-                 }
-             }
-             else if (instance is Stack<TDeclaredProperty> instanceOfStack)
-             {
-                 foreach (TDeclaredProperty item in sourceList)
-                 {
-                     instanceOfStack.Push(item);
-                 }
-                 return instanceOfStack;
-             }
-             else if (instance is Queue<TDeclaredProperty> instanceOfQueue)
+         public override object CreateEnumerableAddMethod(MethodInfo addMethod, object target)
+         {
+             if (target is ICollection<TDeclaredProperty> collection && collection.IsReadOnly)
              {
-                 foreach (TDeclaredProperty item in sourceList)
-                 {
-                     instanceOfQueue.Enqueue(item);
-                 }
-                 return instanceOfQueue;
+                 return null;
              }
  
-             // TODO (https://github.com/dotnet/corefx/issues/40479):
-             // Use reflection to support types implementing Stack or Queue.
+             return Options.MemberAccessorStrategy.CreateAddDelegate<TDeclaredProperty>(addMethod, target);
+         }
  
-             throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
-                 collectionPropertyInfo.DeclaredPropertyType,
-                 collectionPropertyInfo.ParentClassType,
-                 collectionPropertyInfo.PropertyInfo);
+         public override void AddObjectToEnumerableWithReflection(object addMethodDelegate, object value)
+         {
+             Debug.Assert((_elementPropertyInfo ?? ElementClassInfo.PolicyProperty) != null);
+             (_elementPropertyInfo ?? ElementClassInfo.PolicyProperty).AddObjectToParentEnumerable(addMethodDelegate, value);
          }
  
-         public override object CreateDerivedDictionaryInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary)
+         public override void AddObjectToParentEnumerable(object addMethodDelegate, object value)
          {
-             // Implementing types that don't have default constructors are not supported for deserialization.
-             if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
-             {
-                 throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
-                     collectionPropertyInfo.DeclaredPropertyType,
-                     collectionPropertyInfo.ParentClassType,
-                     collectionPropertyInfo.PropertyInfo);
-             }
+             ((Action<TDeclaredProperty>)addMethodDelegate)((TDeclaredProperty)value);
+         }
  
-             object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();
+         public override void AddObjectToDictionary(object target, string key, object value)
+         {
+             Debug.Assert((_elementPropertyInfo ?? ElementClassInfo.PolicyProperty) != null);
+             (_elementPropertyInfo ?? ElementClassInfo.PolicyProperty).AddObjectToParentDictionary(target, key, value);
+         }
  
-             if (instance is IDictionary instanceOfIDictionary)
+         public override void AddObjectToParentDictionary(object target, string key, object value)
+         {
+             if (target is IDictionary<string, TDeclaredProperty> genericDict)
              {
-                 if (!instanceOfIDictionary.IsReadOnly)
-                 {
-                     foreach (DictionaryEntry entry in sourceDictionary)
-                     {
-                         instanceOfIDictionary.Add((string)entry.Key, entry.Value);
-                     }
-                     return instanceOfIDictionary;
-                 }
+                 Debug.Assert(!genericDict.IsReadOnly);
+                 genericDict[key] = (TDeclaredProperty)value;
              }
-             else if (instance is IDictionary<string, TDeclaredProperty> instanceOfGenericIDictionary)
+             else
              {
-                 if (!instanceOfGenericIDictionary.IsReadOnly)
-                 {
-                     foreach (DictionaryEntry entry in sourceDictionary)
-                     {
-                         instanceOfGenericIDictionary.Add((string)entry.Key, (TDeclaredProperty)entry.Value);
-                     }
-                     return instanceOfGenericIDictionary;
-                 }
+                 throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(target.GetType(), parentType: null, memberInfo: null);
              }
+         }
  
-             // TODO (https://github.com/dotnet/corefx/issues/40479):
-             // Use reflection to support types implementing SortedList and maybe immutable dictionaries.
-             // Types implementing SortedList and immutable dictionaries will fail here.
-             throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
-                 collectionPropertyInfo.DeclaredPropertyType,
-                 collectionPropertyInfo.ParentClassType,
-                 collectionPropertyInfo.PropertyInfo);
+         public override bool CanPopulateDictionary(object target)
+         {
+             SetPropertyInfoForObjectElement();
+             Debug.Assert((_elementPropertyInfo ?? ElementClassInfo.PolicyProperty) != null);
+             return (_elementPropertyInfo ?? ElementClassInfo.PolicyProperty).ParentDictionaryCanBePopulated(target);
          }
  
-         public override IEnumerable CreateIEnumerableInstance(ref ReadStack state, Type parentType, IList sourceList)
+         public override bool ParentDictionaryCanBePopulated(object target)
          {
-             if (parentType.IsGenericType)
+             if (target is IDictionary<string, TDeclaredProperty> genericDict && !genericDict.IsReadOnly)
              {
-                 Type genericTypeDefinition = parentType.GetGenericTypeDefinition();
-                 IEnumerable<TDeclaredProperty> items = CreateGenericTDeclaredPropertyIEnumerable(sourceList);
-                 if (genericTypeDefinition == typeof(Stack<>))
-                 {
-                     return new Stack<TDeclaredProperty>(items);
-                 }
-                 else if (genericTypeDefinition == typeof(Queue<>))
-                 {
-                     return new Queue<TDeclaredProperty>(items);
-                 }
-                 else if (genericTypeDefinition == typeof(HashSet<>))
-                 {
-                     return new HashSet<TDeclaredProperty>(items);
-                 }
-                 else if (genericTypeDefinition == typeof(LinkedList<>))
-                 {
-                     return new LinkedList<TDeclaredProperty>(items);
-                 }
-                 else if (genericTypeDefinition == typeof(SortedSet<>))
-                 {
-                     return new SortedSet<TDeclaredProperty>(items);
-                 }
-                 return (IEnumerable)Activator.CreateInstance(parentType, items);
+                 return true;
              }
-             else
+             else if (target is IDictionary dict && !dict.IsReadOnly)
              {
-                 if (parentType == typeof(ArrayList))
-                 {
-                     return new ArrayList(sourceList);
-                 }
-                 // Stack and Queue go into this condition, until we support with reflection.
-                 else
+                 Type genericDictType = target.GetType().GetInterface("System.Collections.Generic.IDictionary`2") ??
+                     target.GetType().GetInterface("System.Collections.Generic.IReadOnlyDictionary`2");
+                 if (genericDictType != null && genericDictType.GetGenericArguments()[0] != typeof(string))
                  {
-                     return (IEnumerable)Activator.CreateInstance(parentType, sourceList);
+                     return false;
                  }
+                 return true;
              }
+             return false;
          }
  
-         public override IDictionary CreateIDictionaryInstance(ref ReadStack state, Type parentType, IDictionary sourceDictionary)
+         public override IList CreateConverterList()
          {
-             if (parentType.FullName == JsonClassInfo.HashtableTypeName)
-             {
-                 return new Hashtable(sourceDictionary);
-             }
-             // SortedList goes into this condition, unless we add a ref to System.Collections.NonGeneric.
-             else
-             {
-                 return (IDictionary)Activator.CreateInstance(parentType, sourceDictionary);
-             }
+             return new List<TDeclaredProperty>();
+         }
+         public override IDictionary CreateConverterDictionary()
+         {
+             return new Dictionary<string, TDeclaredProperty>();
          }
  
          // Creates an IEnumerable<TDeclaredPropertyType> and populates it with the items in the
@@@ -27,7 -25,7 +25,7 @@@ namespace System.Text.Jso
              JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;
              if (jsonPropertyInfo == null)
              {
-                 jsonPropertyInfo = JsonClassInfo.CreateRootProperty(state.Current.JsonClassInfo.Type, options);
 -                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options);
++                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootProperty(options);
              }
              else if (state.Current.JsonClassInfo.ClassType == ClassType.Unknown)
              {
@@@ -17,7 -17,7 +17,7 @@@ namespace System.Text.Jso
              JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;
              if (jsonPropertyInfo == null)
              {
-                 jsonPropertyInfo = JsonClassInfo.CreateRootProperty(state.Current.JsonClassInfo.Type, options);
 -                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options);
++                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootProperty(options);
              }
  
              Debug.Assert(jsonPropertyInfo != null);
@@@ -20,7 -20,7 +20,7 @@@ namespace System.Text.Jso
              JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;
              if (jsonPropertyInfo == null)
              {
-                 jsonPropertyInfo = JsonClassInfo.CreateRootProperty(state.Current.JsonClassInfo.Type, options);
 -                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options);
++                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootProperty(options);
              }
              else if (state.Current.JsonClassInfo.ClassType == ClassType.Unknown)
              {