using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Reflection; using DPumpHydr.WinFrmUI.WenSkin.Json.Utilities; namespace DPumpHydr.WinFrmUI.WenSkin.Json.Serialization { /// /// Contract details for a used by the . /// public class JsonArrayContract : JsonContainerContract { private readonly Type _genericCollectionDefinitionType; private Type _genericWrapperType; private ObjectConstructor _genericWrapperCreator; private Func _genericTemporaryCollectionCreator; private readonly ConstructorInfo _parameterizedConstructor; private ObjectConstructor _parameterizedCreator; private ObjectConstructor _overrideCreator; /// /// Gets the of the collection items. /// /// The of the collection items. public Type CollectionItemType { get; private set; } /// /// Gets a value indicating whether the collection type is a multidimensional array. /// /// true if the collection type is a multidimensional array; otherwise, false. public bool IsMultidimensionalArray { get; private set; } internal bool IsArray { get; private set; } internal bool ShouldCreateWrapper { get; private set; } internal bool CanDeserialize { get; private set; } internal ObjectConstructor ParameterizedCreator { get { if (_parameterizedCreator == null) { _parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(_parameterizedConstructor); } return _parameterizedCreator; } } /// /// Gets or sets the function used to create the object. When set this function will override . /// /// The function used to create the object. public ObjectConstructor OverrideCreator { get { return _overrideCreator; } set { _overrideCreator = value; CanDeserialize = true; } } /// /// Gets a value indicating whether the creator has a parameter with the collection values. /// /// true if the creator has a parameter with the collection values; otherwise, false. public bool HasParameterizedCreator { get; set; } internal bool HasParameterizedCreatorInternal { get { if (!HasParameterizedCreator && _parameterizedCreator == null) { return _parameterizedConstructor != null; } return true; } } /// /// Initializes a new instance of the class. /// /// The underlying type for the contract. public JsonArrayContract(Type underlyingType) : base(underlyingType) { ContractType = JsonContractType.Array; IsArray = base.CreatedType.IsArray; bool canDeserialize; Type implementingType; if (IsArray) { CollectionItemType = ReflectionUtils.GetCollectionItemType(base.UnderlyingType); IsReadOnlyOrFixedSize = true; _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); canDeserialize = true; IsMultidimensionalArray = IsArray && base.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)) { base.CreatedType = typeof(List); } 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<>))) { base.CreatedType = typeof(List<>).MakeGenericType(CollectionItemType); } if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(ISet<>))) { base.CreatedType = typeof(HashSet<>).MakeGenericType(CollectionItemType); } _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType); canDeserialize = true; ShouldCreateWrapper = true; } else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IReadOnlyCollection<>), out implementingType)) { CollectionItemType = implementingType.GetGenericArguments()[0]; if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IReadOnlyCollection<>)) || ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IReadOnlyList<>))) { base.CreatedType = typeof(ReadOnlyCollection<>).MakeGenericType(CollectionItemType); } _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(base.CreatedType, CollectionItemType); IsReadOnlyOrFixedSize = true; canDeserialize = HasParameterizedCreatorInternal; } else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IEnumerable<>), out implementingType)) { CollectionItemType = implementingType.GetGenericArguments()[0]; if (ReflectionUtils.IsGenericDefinition(base.UnderlyingType, typeof(IEnumerable<>))) { base.CreatedType = typeof(List<>).MakeGenericType(CollectionItemType); } _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType); if (!HasParameterizedCreatorInternal && underlyingType.Name == "FSharpList`1") { FSharpUtils.EnsureInitialized(underlyingType.Assembly()); _parameterizedCreator = FSharpUtils.CreateSeq(CollectionItemType); } if (underlyingType.IsGenericType() && underlyingType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { _genericCollectionDefinitionType = implementingType; IsReadOnlyOrFixedSize = false; ShouldCreateWrapper = false; canDeserialize = true; } else { _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); IsReadOnlyOrFixedSize = true; ShouldCreateWrapper = true; canDeserialize = HasParameterizedCreatorInternal; } } else { canDeserialize = false; ShouldCreateWrapper = true; } CanDeserialize = canDeserialize; if (ImmutableCollectionsUtils.TryBuildImmutableForArrayContract(underlyingType, CollectionItemType, out var createdType, out var parameterizedCreator)) { base.CreatedType = createdType; _parameterizedCreator = parameterizedCreator; IsReadOnlyOrFixedSize = true; CanDeserialize = true; } } internal IWrappedCollection CreateWrapper(object list) { if (_genericWrapperCreator == null) { _genericWrapperType = typeof(CollectionWrapper<>).MakeGenericType(CollectionItemType); Type type = ((!ReflectionUtils.InheritsGenericDefinition(_genericCollectionDefinitionType, typeof(List<>)) && !(_genericCollectionDefinitionType.GetGenericTypeDefinition() == typeof(IEnumerable<>))) ? _genericCollectionDefinitionType : typeof(ICollection<>).MakeGenericType(CollectionItemType)); ConstructorInfo constructor = _genericWrapperType.GetConstructor(new Type[1] { type }); _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructor); } return (IWrappedCollection)_genericWrapperCreator(list); } internal IList CreateTemporaryCollection() { if (_genericTemporaryCollectionCreator == null) { Type type = ((IsMultidimensionalArray || CollectionItemType == null) ? typeof(object) : CollectionItemType); Type type2 = typeof(List<>).MakeGenericType(type); _genericTemporaryCollectionCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor(type2); } return (IList)_genericTemporaryCollectionCreator(); } } }