/// <summary> /// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class. /// </summary> /// <param name="underlyingType">The underlying type for the contract.</param> public JsonDictionaryContract(Type underlyingType) : base(underlyingType) { ContractType = JsonContractType.Dictionary; Type keyType; Type valueType; if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IDictionary<,>), out _genericCollectionDefinitionType)) { keyType = _genericCollectionDefinitionType.GetGenericArguments()[0]; valueType = _genericCollectionDefinitionType.GetGenericArguments()[1]; if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IDictionary<,>))) { CreatedType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); } #if !(NET40 || NET35 || NET20 || PORTABLE40) IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyDictionary<,>)); #endif } #if !(NET40 || NET35 || NET20 || PORTABLE40) else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IReadOnlyDictionary<,>), out _genericCollectionDefinitionType)) { keyType = _genericCollectionDefinitionType.GetGenericArguments()[0]; valueType = _genericCollectionDefinitionType.GetGenericArguments()[1]; if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IReadOnlyDictionary<,>))) { CreatedType = typeof(ReadOnlyDictionary<,>).MakeGenericType(keyType, valueType); } IsReadOnlyOrFixedSize = true; } #endif else { ReflectionUtils.GetDictionaryKeyValueTypes(UnderlyingType, out keyType, out valueType); if (UnderlyingType == typeof(IDictionary)) { CreatedType = typeof(Dictionary<object, object>); } } if (keyType != null && valueType != null) { _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType)); #if !(NET35 || NET20) if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpMapTypeName) { FSharpUtils.EnsureInitialized(underlyingType.Assembly()); _parameterizedCreator = FSharpUtils.CreateMap(keyType, valueType); } #endif } ShouldCreateWrapper = !typeof(IDictionary).IsAssignableFrom(CreatedType); DictionaryKeyType = keyType; DictionaryValueType = valueType; #if (NET20 || NET35) if (DictionaryValueType != null && ReflectionUtils.IsNullableType(DictionaryValueType)) { Type tempDictioanryType; // bug in .NET 2.0 & 3.5 that Dictionary<TKey, Nullable<TValue>> throws an error when adding null via IDictionary[key] = object // wrapper will handle calling Add(T) instead if (ReflectionUtils.InheritsGenericDefinition(CreatedType, typeof(Dictionary<,>), out tempDictioanryType)) { ShouldCreateWrapper = true; } } #endif #if !(NET20 || NET35 || NET40) Type immutableCreatedType; ObjectConstructor<object> immutableParameterizedCreator; if (ImmutableCollectionsUtils.TryBuildImmutableForDictionaryContract(underlyingType, DictionaryKeyType, DictionaryValueType, out immutableCreatedType, out immutableParameterizedCreator)) { CreatedType = immutableCreatedType; _parameterizedCreator = immutableParameterizedCreator; IsReadOnlyOrFixedSize = true; } #endif }
/// <summary> /// Initializes a new instance of the <see cref="JsonArrayContract"/> class. /// </summary> /// <param name="underlyingType">The underlying type for the contract.</param> public JsonArrayContract(Type underlyingType) : base(underlyingType) { ContractType = JsonContractType.Array; IsArray = CreatedType.IsArray; bool canDeserialize; Type tempCollectionType; if (IsArray) { CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType); IsReadOnlyOrFixedSize = true; _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); canDeserialize = true; IsMultidimensionalArray = (IsArray && UnderlyingType.GetArrayRank() > 1); } else if (typeof(IList).IsAssignableFrom(underlyingType)) { if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType)) { CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0]; } else { CollectionItemType = ReflectionUtils.GetCollectionItemType(underlyingType); } if (underlyingType == typeof(IList)) { CreatedType = typeof(List<object>); } if (CollectionItemType != null) { _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType); } IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyCollection<>)); canDeserialize = true; } else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType)) { CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0]; if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(ICollection<>)) || ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IList<>))) { CreatedType = typeof(List<>).MakeGenericType(CollectionItemType); } #if !(NET20 || NET35 || PORTABLE40) if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(ISet<>))) { CreatedType = typeof(HashSet<>).MakeGenericType(CollectionItemType); } #endif _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType); canDeserialize = true; ShouldCreateWrapper = true; } #if !(NET40 || NET35 || NET20 || PORTABLE40) else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IReadOnlyCollection<>), out tempCollectionType)) { CollectionItemType = tempCollectionType.GetGenericArguments()[0]; if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IReadOnlyCollection<>)) || ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IReadOnlyList<>))) { CreatedType = typeof(ReadOnlyCollection<>).MakeGenericType(CollectionItemType); } _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, CollectionItemType); IsReadOnlyOrFixedSize = true; canDeserialize = HasParameterizedCreatorInternal; } #endif else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IEnumerable<>), out tempCollectionType)) { CollectionItemType = tempCollectionType.GetGenericArguments()[0]; if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IEnumerable<>))) { CreatedType = typeof(List<>).MakeGenericType(CollectionItemType); } _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType); #if !(NET35 || NET20) if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpListTypeName) { FSharpUtils.EnsureInitialized(underlyingType.Assembly()); _parameterizedCreator = FSharpUtils.CreateSeq(CollectionItemType); } #endif if (underlyingType.IsGenericType() && underlyingType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { _genericCollectionDefinitionType = tempCollectionType; IsReadOnlyOrFixedSize = false; ShouldCreateWrapper = false; canDeserialize = true; } else { _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); IsReadOnlyOrFixedSize = true; ShouldCreateWrapper = true; canDeserialize = HasParameterizedCreatorInternal; } } else { // types that implement IEnumerable and nothing else canDeserialize = false; ShouldCreateWrapper = true; } CanDeserialize = canDeserialize; #if (NET20 || NET35) if (CollectionItemType != null && ReflectionUtils.IsNullableType(CollectionItemType)) { // bug in .NET 2.0 & 3.5 that List<Nullable<T>> throws an error when adding null via IList.Add(object) // wrapper will handle calling Add(T) instead if (ReflectionUtils.InheritsGenericDefinition(CreatedType, typeof(List<>), out tempCollectionType) || (IsArray && !IsMultidimensionalArray)) { ShouldCreateWrapper = true; } } #endif #if !(NET20 || NET35 || NET40) Type immutableCreatedType; ObjectConstructor<object> immutableParameterizedCreator; if (ImmutableCollectionsUtils.TryBuildImmutableForArrayContract(underlyingType, CollectionItemType, out immutableCreatedType, out immutableParameterizedCreator)) { CreatedType = immutableCreatedType; _parameterizedCreator = immutableParameterizedCreator; IsReadOnlyOrFixedSize = true; CanDeserialize = true; } #endif }