示例#1
0
        internal static T Create <T>(IDefaultData defaultData, ObjectCreationStrategy objectCreationStrategy)
        {
            var expectedType = typeof(T);
            var genericType  = expectedType.GetGenericTypeDefinition();

            return(expectedType.IsInterface ?
                   (T)GenericInterfaceCollectionTypes.GetValueOrDefault(genericType)?.Invoke(expectedType, defaultData, objectCreationStrategy) :
                   (T)GenericCollectionTypes.GetValueOrDefault(genericType)?.Invoke(expectedType, defaultData, objectCreationStrategy));
        }
示例#2
0
        private static bool TryCreateCollectionTraitsForIEnumerableT(
            Type source,
            GenericCollectionTypes genericTypes,
            CollectionTraitOptions options,
            MethodInfo getMethod,
            out CollectionTraits result
            )
        {
            var elementType = genericTypes.IEnumerableT.GetGenericArguments()[0];
            var addMethod   = GetAddMethod(source, elementType, options);

            if (addMethod == null && ((options & CollectionTraitOptions.AllowNonCollectionEnumerableTypes) != 0))
            {
                // This should be non collection object isntead of "unappendable" collection.
                result = default(CollectionTraits);
                return(false);
            }

            CollectionDetailedKind kind = CollectionDetailedKind.GenericEnumerable;

            if (genericTypes.IListT != null)
            {
                kind = CollectionDetailedKind.GenericList;
            }
#if !NETFX_35 && !UNITY
            else if (genericTypes.ISetT != null)
            {
                kind = CollectionDetailedKind.GenericSet;
            }
#endif // !NETFX_35 && !UNITY
            else if (genericTypes.ICollectionT != null)
            {
                kind = CollectionDetailedKind.GenericCollection;
            }
#if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE)
            else if (genericTypes.IReadOnlyListT != null)
            {
                kind = CollectionDetailedKind.GenericReadOnlyList;
            }
            else if (genericTypes.IReadOnlyCollectionT != null)
            {
                kind = CollectionDetailedKind.GenericReadOnlyCollection;
            }
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )

            result =
                new CollectionTraits(
                    kind,
                    elementType,
                    getMethod ?? GetGetEnumeratorMethodFromElementType(source, elementType, options),
                    addMethod,
                    GetCountGetterMethod(source, elementType, options)
                    );
            return(true);
        }
示例#3
0
        private static bool DetermineCollectionInterfaces(
            Type type,
            ref GenericCollectionTypes genericTypes,
            ref Type idictionary,
            ref Type ilist,
            ref Type icollection,
            ref Type ienumerable
            )
        {
            if (type.GetIsGenericType())
            {
                var genericTypeDefinition = type.GetGenericTypeDefinition();
                if (genericTypeDefinition == typeof(IDictionary <,>))
                {
                    if (genericTypes.IDictionaryT != null)
                    {
                        return(false);
                    }

                    genericTypes.IDictionaryT = type;
                }
#if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE)
                else if (genericTypeDefinition == typeof(IReadOnlyDictionary <,>))
                {
                    if (genericTypes.IReadOnlyDictionaryT != null)
                    {
                        return(false);
                    }

                    genericTypes.IReadOnlyDictionaryT = type;
                }
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
                else if (genericTypeDefinition == typeof(IList <>))
                {
                    if (genericTypes.IListT != null)
                    {
                        return(false);
                    }

                    genericTypes.IListT = type;
                }
#if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE)
                else if (genericTypeDefinition == typeof(IReadOnlyList <>))
                {
                    if (genericTypes.IReadOnlyListT != null)
                    {
                        return(false);
                    }

                    genericTypes.IReadOnlyListT = type;
                }
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
#if !NETFX_35 && !UNITY
                else if (genericTypeDefinition == typeof(ISet <>))
                {
                    if (genericTypes.ISetT != null)
                    {
                        return(false);
                    }

                    genericTypes.ISetT = type;
                }
#endif // !NETFX_35 && !UNITY
                else if (genericTypeDefinition == typeof(ICollection <>))
                {
                    if (genericTypes.ICollectionT != null)
                    {
                        return(false);
                    }

                    genericTypes.ICollectionT = type;
                }
#if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE)
                else if (genericTypeDefinition == typeof(IReadOnlyCollection <>))
                {
                    if (genericTypes.IReadOnlyCollectionT != null)
                    {
                        return(false);
                    }

                    genericTypes.IReadOnlyCollectionT = type;
                }
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
                else if (genericTypeDefinition == typeof(IEnumerable <>))
                {
                    if (genericTypes.IEnumerableT != null)
                    {
                        return(false);
                    }

                    genericTypes.IEnumerableT = type;
                }
            }
            else
            {
                if (type == typeof(IDictionary))
                {
                    idictionary = type;
                }
                else if (type == typeof(IList))
                {
                    ilist = type;
                }
                else if (type == typeof(ICollection))
                {
                    icollection = type;
                }
                else if (type == typeof(IEnumerable))
                {
                    ienumerable = type;
                }
            }

            return(true);
        }
示例#4
0
        private static bool TryCreateCollectionTraitsForHasGetEnumeratorType(
            Type source,
            CollectionTraitOptions options,
            MethodInfo getEnumerator,
            out CollectionTraits result
            )
        {
            if (source.Implements(typeof(IDictionary <,>))
#if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE)
                || source.Implements(typeof(IReadOnlyDictionary <,>))
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
                )
            {
                var ienumetaorT =
                    getEnumerator.ReturnType.GetInterfaces()
                    .FirstOrDefault(@interface =>
                                    @interface.GetIsGenericType() && @interface.GetGenericTypeDefinition() == typeof(IEnumerator <>)
                                    );
                if (ienumetaorT != null)
                {
                    var elementType = ienumetaorT.GetGenericArguments()[0];
                    var elementTypeGenericArguments = elementType.GetGenericArguments();

                    result =
                        new CollectionTraits(
#if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE)
                            source.Implements(typeof(IDictionary <,>))
                                                        ? CollectionDetailedKind.GenericDictionary
                                                        : CollectionDetailedKind.GenericReadOnlyDictionary,
#else
                            CollectionDetailedKind.GenericDictionary,
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
                            elementType,
                            getEnumerator,
                            GetAddMethod(source, elementTypeGenericArguments[0], elementTypeGenericArguments [1], options),
                            GetCountGetterMethod(source, elementType, options)
                            );

                    return(true);
                }
            }

            if (source.IsAssignableTo(typeof(IDictionary)))
            {
                result =
                    new CollectionTraits(
                        CollectionDetailedKind.NonGenericDictionary,
                        typeof(DictionaryEntry),
                        getEnumerator,
                        GetAddMethod(source, typeof(object), typeof(object), options),
                        GetCountGetterMethod(source, typeof(object), options)
                        );

                return(true);
            }

            // Block to limit variable scope
            {
                var ienumetaorT =
                    IsIEnumeratorT(getEnumerator.ReturnType)
                                        ? getEnumerator.ReturnType
                                        : getEnumerator.ReturnType.GetInterfaces().FirstOrDefault(IsIEnumeratorT);

                if (ienumetaorT != null)
                {
                    // Get the open generic types once
                    Type[] genericInterfaces =
                        source.GetInterfaces()
                        .Where(i => i.GetIsGenericType())
                        .Select(i => i.GetGenericTypeDefinition())
                        .ToArray();

                    var genericTypes = new GenericCollectionTypes();
                    genericTypes.IEnumerableT = ienumetaorT;
                    genericTypes.ICollectionT = genericInterfaces.FirstOrDefault(i => i == typeof(ICollection <>));
                    genericTypes.IListT       = genericInterfaces.FirstOrDefault(i => i == typeof(IList <>));

#if !NETFX_35 && !UNITY
                    genericTypes.ISetT = genericInterfaces.FirstOrDefault(i => i == typeof(ISet <>));
#endif // !NETFX_35 && !UNITY
#if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE)
                    genericTypes.IReadOnlyCollectionT = genericInterfaces.FirstOrDefault(i => i == typeof(IReadOnlyCollection <>));
                    genericTypes.IReadOnlyListT       = genericInterfaces.FirstOrDefault(i => i == typeof(IReadOnlyList <>));
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )

                    return(TryCreateCollectionTraitsForIEnumerableT(source, genericTypes, options, getEnumerator, out result));
                }
            }

            result = default(CollectionTraits);
            return(false);
        }
示例#5
0
        public static CollectionTraits GetCollectionTraits(this Type source, CollectionTraitOptions options, bool allowNonCollectionEnumerableTypes)
        {
#if DEBUG
            Contract.Assert(!source.GetContainsGenericParameters(), "!source.GetContainsGenericParameters()");
#endif // DEBUG

            /*
             * SPEC
             * If the object has single public method TEnumerator GetEnumerator() ( where TEnumerator implements IEnumerator<TItem>),
             * then the object is considered as the collection of TItem.
             * When the object is considered as the collection of TItem, TItem is KeyValuePair<TKey,TValue>,
             * and the object implements IDictionary<TKey,TValue>, then the object is considered as dictionary of TKey and TValue.
             * Else, if the object has single public method IEnumerator GetEnumerator(), then the object is considered as the collection of Object.
             * When it also implements IDictionary, however, it is considered dictionary of Object and Object.
             * Otherwise, that means it implements multiple collection interface, is following.
             * First, if the object implements IDictionary<MessagePackObject,MessagePackObject>, then it is considered as MPO dictionary.
             * Second, if the object implements IEnumerable<MPO>, then it is considered as MPO dictionary.
             * Third, if the object implement SINGLE IDictionary<TKey,TValue> and multiple IEnumerable<T>, then it is considered as dictionary of TKey and TValue.
             * Fourth, the object is considered as UNSERIALIZABLE member. This behavior similer to DataContract serialization behavor
             * (see http://msdn.microsoft.com/en-us/library/aa347850.aspx ).
             */

            if (!source.IsAssignableTo(typeof(IEnumerable)))
            {
                return(CollectionTraits.NotCollection);
            }

            if (source.IsArray)
            {
                return
                    (new CollectionTraits(
                         CollectionDetailedKind.Array,
                         source.GetElementType(),
                         null,                        // Never used for array.
                         null,                        // Never used for array.
                         null                         // Never used for array.
                         ));
            }

            // If the type is an interface then a concrete collection has to be
            // made for it (if the interface is a collection type), therefore,
            // ignore the check for an add method
            if (!source.GetIsInterface() && allowNonCollectionEnumerableTypes)
            {
                options = options | CollectionTraitOptions.AllowNonCollectionEnumerableTypes;
            }

            MethodInfo getEnumerator = source.GetMethod("GetEnumerator", ReflectionAbstractions.EmptyTypes);
            if (getEnumerator != null && getEnumerator.ReturnType.IsAssignableTo(typeof(IEnumerator)))
            {
                // If public 'GetEnumerator' is found, it is primary collection traits.
                CollectionTraits result;
                if (TryCreateCollectionTraitsForHasGetEnumeratorType(source, options, getEnumerator, out result))
                {
                    return(result);
                }
            }

            GenericCollectionTypes genericTypes = new GenericCollectionTypes();
            Type ienumerable = null;
            Type icollection = null;
            Type ilist       = null;
            Type idictionary = null;

            var sourceInterfaces = source.FindInterfaces(FilterCollectionType, null);
            if (source.GetIsInterface() && FilterCollectionType(source, null))
            {
                var originalSourceInterfaces    = sourceInterfaces.ToArray();
                var concatenatedSourceInterface = new Type[originalSourceInterfaces.Length + 1];
                concatenatedSourceInterface[0] = source;
                for (int i = 0; i < originalSourceInterfaces.Length; i++)
                {
                    concatenatedSourceInterface[i + 1] = originalSourceInterfaces[i];
                }

                sourceInterfaces = concatenatedSourceInterface;
            }

            foreach (var type in sourceInterfaces)
            {
                CollectionTraits result;
                if (TryCreateGenericCollectionTraits(source, type, options, out result))
                {
                    return(result);
                }

                if (!DetermineCollectionInterfaces(
                        type,
                        ref genericTypes,
                        ref idictionary,
                        ref ilist,
                        ref icollection,
                        ref ienumerable
                        )
                    )
                {
                    return(CollectionTraits.Unserializable);
                }
            }

            if (genericTypes.IDictionaryT != null)
            {
                var genericArguments = genericTypes.IDictionaryT.GetGenericArguments();
                var elementType      = typeof(KeyValuePair <,>).MakeGenericType(genericArguments);

                return
                    (new CollectionTraits(
                         CollectionDetailedKind.GenericDictionary,
                         elementType,
                         GetGetEnumeratorMethodFromElementType(source, elementType, options),
                         GetAddMethod(source, genericArguments[0], genericArguments[1], options),
                         GetCountGetterMethod(source, elementType, options)
                         ));
            }

#if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE)
            if (genericTypes.IReadOnlyDictionaryT != null)
            {
                var elementType = typeof(KeyValuePair <,>).MakeGenericType(genericTypes.IReadOnlyDictionaryT.GetGenericArguments());
                return
                    (new CollectionTraits(
                         CollectionDetailedKind.GenericReadOnlyDictionary,
                         elementType,
                         GetGetEnumeratorMethodFromElementType(source, elementType, options),
                         null,                        // add
                         GetCountGetterMethod(source, elementType, options)
                         ));
            }
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )

            if (genericTypes.IEnumerableT != null)
            {
                CollectionTraits traits;
                if (TryCreateCollectionTraitsForIEnumerableT(source, genericTypes, options, null, out traits))
                {
                    return(traits);
                }
            }

            if (idictionary != null)
            {
                return
                    (new CollectionTraits(
                         CollectionDetailedKind.NonGenericDictionary,
                         typeof(object),
                         GetGetEnumeratorMethodFromEnumerableType(source, idictionary, options),
                         GetAddMethod(source, typeof(object), typeof(object), options),
                         GetCountGetterMethod(source, typeof(object), options)
                         ));
            }

            if (ienumerable != null)
            {
                var addMethod = GetAddMethod(source, typeof(object), options | CollectionTraitOptions.WithAddMethod);
                if (addMethod != null || ((options & CollectionTraitOptions.AllowNonCollectionEnumerableTypes) == 0))
                {
                    // This should be appendable or unappendable collection
                    return
                        (new CollectionTraits(
                             (ilist != null)
                                                        ? CollectionDetailedKind.NonGenericList
                                                        : (icollection != null)
                                                        ? CollectionDetailedKind.NonGenericCollection
                                                        : CollectionDetailedKind.NonGenericEnumerable,
                             typeof(object),
                             GetGetEnumeratorMethodFromEnumerableType(source, ienumerable, options),
                             addMethod,
                             GetCountGetterMethod(source, typeof(object), options)
                             ));
                }
            }

            return(CollectionTraits.NotCollection);
        }
		public static CollectionTraits GetCollectionTraits( this Type source, CollectionTraitOptions options, bool allowNonCollectionEnumerableTypes )
		{
#if DEBUG
			Contract.Assert( !source.GetContainsGenericParameters(), "!source.GetContainsGenericParameters()" );
#endif // DEBUG
			/*
			 * SPEC
			 * If the object has single public method TEnumerator GetEnumerator() ( where TEnumerator implements IEnumerator<TItem>),
			 * then the object is considered as the collection of TItem.
			 * When the object is considered as the collection of TItem, TItem is KeyValuePair<TKey,TValue>, 
			 * and the object implements IDictionary<TKey,TValue>, then the object is considered as dictionary of TKey and TValue.
			 * Else, if the object has single public method IEnumerator GetEnumerator(), then the object is considered as the collection of Object.
			 * When it also implements IDictionary, however, it is considered dictionary of Object and Object.
			 * Otherwise, that means it implements multiple collection interface, is following.
			 * First, if the object implements IDictionary<MessagePackObject,MessagePackObject>, then it is considered as MPO dictionary.
			 * Second, if the object implements IEnumerable<MPO>, then it is considered as MPO dictionary.
			 * Third, if the object implement SINGLE IDictionary<TKey,TValue> and multiple IEnumerable<T>, then it is considered as dictionary of TKey and TValue.
			 * Fourth, the object is considered as UNSERIALIZABLE member. This behavior similer to DataContract serialization behavor
			 * (see http://msdn.microsoft.com/en-us/library/aa347850.aspx ).
			 */

			if ( !source.IsAssignableTo( typeof( IEnumerable ) ) )
			{
				return CollectionTraits.NotCollection;
			}

			if ( source.IsArray )
			{
				return
					new CollectionTraits(
						CollectionDetailedKind.Array,
						source.GetElementType(),
						null, // Never used for array.
						null, // Never used for array.
						null  // Never used for array.
					);
			}

			// If the type is an interface then a concrete collection has to be
			// made for it (if the interface is a collection type), therefore,
			// ignore the check for an add method
			if ( !source.GetIsInterface() && allowNonCollectionEnumerableTypes )
			{
				options = options | CollectionTraitOptions.AllowNonCollectionEnumerableTypes;
			}

			MethodInfo getEnumerator = source.GetMethod( "GetEnumerator", ReflectionAbstractions.EmptyTypes );
			if ( getEnumerator != null && getEnumerator.ReturnType.IsAssignableTo( typeof( IEnumerator ) ) )
			{
				// If public 'GetEnumerator' is found, it is primary collection traits.
				CollectionTraits result;
				if ( TryCreateCollectionTraitsForHasGetEnumeratorType( source, options, getEnumerator, out result ) )
				{
					return result;
				}
			}

			GenericCollectionTypes genericTypes = new GenericCollectionTypes();
			Type ienumerable = null;
			Type icollection = null;
			Type ilist = null;
			Type idictionary = null;

			var sourceInterfaces = source.FindInterfaces( FilterCollectionType, null );
			if ( source.GetIsInterface() && FilterCollectionType( source, null ) )
			{
				var originalSourceInterfaces = sourceInterfaces.ToArray();
				var concatenatedSourceInterface = new Type[ originalSourceInterfaces.Length + 1 ];
				concatenatedSourceInterface[ 0 ] = source;
				for ( int i = 0; i < originalSourceInterfaces.Length; i++ )
				{
					concatenatedSourceInterface[ i + 1 ] = originalSourceInterfaces[ i ];
				}

				sourceInterfaces = concatenatedSourceInterface;
			}

			foreach ( var type in sourceInterfaces )
			{
				CollectionTraits result;
				if ( TryCreateGenericCollectionTraits( source, type, options, out result ) )
				{
					return result;
				}

				if ( !DetermineCollectionInterfaces(
						type,
						ref genericTypes,
						ref idictionary,
						ref ilist,
						ref icollection,
						ref ienumerable
					)
				)
				{
					return CollectionTraits.Unserializable;
				}
			}

			if ( genericTypes.IDictionaryT != null )
			{
				var genericArguments = genericTypes.IDictionaryT.GetGenericArguments();
				var elementType = typeof( KeyValuePair<,> ).MakeGenericType( genericArguments );

				return 
					new CollectionTraits(
						CollectionDetailedKind.GenericDictionary,
						elementType,
						GetGetEnumeratorMethodFromElementType( source, elementType, options ),
						GetAddMethod( source, genericArguments[ 0 ], genericArguments[ 1 ], options ),
						GetCountGetterMethod( source, elementType, options )
					);
			}

#if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
			if ( genericTypes.IReadOnlyDictionaryT != null )
			{
				var elementType = typeof( KeyValuePair<,> ).MakeGenericType( genericTypes.IReadOnlyDictionaryT.GetGenericArguments() );
				return
					new CollectionTraits(
						CollectionDetailedKind.GenericReadOnlyDictionary,
						elementType,
						GetGetEnumeratorMethodFromElementType( source, elementType, options ),
						null, // add
						GetCountGetterMethod( source, elementType, options )
					);
			}
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )

			if ( genericTypes.IEnumerableT != null )
			{
				CollectionTraits traits;
				if ( TryCreateCollectionTraitsForIEnumerableT( source, genericTypes, options, null, out traits ) )
				{
					return traits;
				}
			}

			if ( idictionary != null )
			{
				return
					new CollectionTraits(
						CollectionDetailedKind.NonGenericDictionary,
						typeof( object ),
						GetGetEnumeratorMethodFromEnumerableType( source, idictionary, options ),
						GetAddMethod( source, typeof( object ), typeof( object ), options ),
						GetCountGetterMethod( source, typeof( object ), options )
					);
			}

			if ( ienumerable != null )
			{
				var addMethod = GetAddMethod( source, typeof( object ), options | CollectionTraitOptions.WithAddMethod );
				if ( addMethod != null || ( ( options & CollectionTraitOptions.AllowNonCollectionEnumerableTypes ) == 0 ) )
				{
					// This should be appendable or unappendable collection
					return
						new CollectionTraits(
							( ilist != null )
								? CollectionDetailedKind.NonGenericList
								: ( icollection != null )
									? CollectionDetailedKind.NonGenericCollection
									: CollectionDetailedKind.NonGenericEnumerable,
							typeof( object ),
							GetGetEnumeratorMethodFromEnumerableType( source, ienumerable, options ),
							addMethod,
							GetCountGetterMethod( source, typeof( object ), options )
						);
				}
			}

			return CollectionTraits.NotCollection;
		}
		private static bool DetermineCollectionInterfaces(
			Type type,
			ref GenericCollectionTypes genericTypes,
			ref Type idictionary,
			ref Type ilist,
			ref Type icollection,
			ref Type ienumerable
		)
		{
			if ( type.GetIsGenericType() )
			{
				var genericTypeDefinition = type.GetGenericTypeDefinition();
				if ( genericTypeDefinition == typeof( IDictionary<,> ) )
				{
					if ( genericTypes.IDictionaryT != null )
					{
						return false;
					}

					genericTypes.IDictionaryT = type;
				}
#if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
				else if ( genericTypeDefinition == typeof( IReadOnlyDictionary<,> ) )
				{
					if ( genericTypes.IReadOnlyDictionaryT != null )
					{
						return false;
					}

					genericTypes.IReadOnlyDictionaryT = type;
				}
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
				else if ( genericTypeDefinition == typeof( IList<> ) )
				{
					if ( genericTypes.IListT != null )
					{
						return false;
					}

					genericTypes.IListT = type;
				}
#if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
				else if ( genericTypeDefinition == typeof( IReadOnlyList<> ) )
				{
					if ( genericTypes.IReadOnlyListT != null )
					{
						return false;
					}

					genericTypes.IReadOnlyListT = type;
				}
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
#if !NETFX_35 && !UNITY
				else if ( genericTypeDefinition == typeof( ISet<> ) )
				{
					if ( genericTypes.ISetT != null )
					{
						return false;
					}

					genericTypes.ISetT = type;
				}
#endif // !NETFX_35 && !UNITY
				else if ( genericTypeDefinition == typeof( ICollection<> ) )
				{
					if ( genericTypes.ICollectionT != null )
					{
						return false;
					}

					genericTypes.ICollectionT = type;
				}
#if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
				else if ( genericTypeDefinition == typeof( IReadOnlyCollection<> ) )
				{
					if ( genericTypes.IReadOnlyCollectionT != null )
					{
						return false;
					}

					genericTypes.IReadOnlyCollectionT = type;
				}
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
				else if ( genericTypeDefinition == typeof( IEnumerable<> ) )
				{
					if ( genericTypes.IEnumerableT != null )
					{
						return false;
					}

					genericTypes.IEnumerableT = type;
				}
			}
			else
			{
				if ( type == typeof( IDictionary ) )
				{
					idictionary = type;
				}
				else if ( type == typeof( IList ) )
				{
					ilist = type;
				}
				else if ( type == typeof( ICollection ) )
				{
					icollection = type;
				}
				else if ( type == typeof( IEnumerable ) )
				{
					ienumerable = type;
				}
			}

			return true;
		}
		private static bool TryCreateCollectionTraitsForHasGetEnumeratorType(
			Type source,
			CollectionTraitOptions options,
			MethodInfo getEnumerator,
			out CollectionTraits result
		)
		{
			if ( source.Implements( typeof( IDictionary<,> ) )
#if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
				|| source.Implements( typeof( IReadOnlyDictionary<,> ) )
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
			)
			{
				var ienumetaorT =
					getEnumerator.ReturnType.GetInterfaces()
						.FirstOrDefault( @interface => 
												@interface.GetIsGenericType() && @interface.GetGenericTypeDefinition() == typeof( IEnumerator<> ) 
						);
				if ( ienumetaorT != null )
				{
					var elementType = ienumetaorT.GetGenericArguments()[ 0 ];
					var elementTypeGenericArguments = elementType.GetGenericArguments();

					result = 
						new CollectionTraits(
#if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
							source.Implements( typeof( IDictionary<,> ) )
								? CollectionDetailedKind.GenericDictionary
								: CollectionDetailedKind.GenericReadOnlyDictionary,
#else
							CollectionDetailedKind.GenericDictionary,
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
							elementType,
							getEnumerator,
							GetAddMethod( source, elementTypeGenericArguments[ 0 ], elementTypeGenericArguments [ 1 ], options ),
							GetCountGetterMethod( source, elementType, options )
						);

					return true;
				}
			}

			if ( source.IsAssignableTo( typeof( IDictionary ) ) )
			{
				result = 
					new CollectionTraits(
						CollectionDetailedKind.NonGenericDictionary,
						typeof( DictionaryEntry ),
						getEnumerator,
						GetAddMethod( source, typeof( object ), typeof( object ), options ),
						GetCountGetterMethod( source, typeof( object ), options )
					);

				return true;
			}

			// Block to limit variable scope
			{
				var ienumetaorT =
					IsIEnumeratorT( getEnumerator.ReturnType )
						? getEnumerator.ReturnType
						: getEnumerator.ReturnType.GetInterfaces().FirstOrDefault( IsIEnumeratorT );

				if ( ienumetaorT != null )
				{
					// Get the open generic types once
					Type[] genericInterfaces =
						source.GetInterfaces()
							.Where( i => i.GetIsGenericType() )
							.Select( i => i.GetGenericTypeDefinition() )
							.ToArray();

					var genericTypes = new GenericCollectionTypes();
					genericTypes.IEnumerableT = ienumetaorT;
					genericTypes.ICollectionT = genericInterfaces.FirstOrDefault( i => i == typeof(ICollection<>) );
					genericTypes.IListT = genericInterfaces.FirstOrDefault( i => i == typeof(IList<>) );

#if !NETFX_35 && !UNITY
					genericTypes.ISetT = genericInterfaces.FirstOrDefault( i => i == typeof(ISet<>) );
#endif // !NETFX_35 && !UNITY
#if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
					genericTypes.IReadOnlyCollectionT = genericInterfaces.FirstOrDefault( i => i == typeof(IReadOnlyCollection<>) );
					genericTypes.IReadOnlyListT = genericInterfaces.FirstOrDefault( i => i == typeof(IReadOnlyList<>) );
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )

					return TryCreateCollectionTraitsForIEnumerableT( source, genericTypes, options, getEnumerator, out result );
				}
			}

			result = default( CollectionTraits );
			return false;
		}
		private static bool TryCreateCollectionTraitsForIEnumerableT(
			Type source,
			GenericCollectionTypes genericTypes,
			CollectionTraitOptions options,
			MethodInfo getMethod,
			out CollectionTraits result
		)
		{
			var elementType = genericTypes.IEnumerableT.GetGenericArguments()[ 0 ];
			var addMethod = GetAddMethod( source, elementType, options );
			if ( addMethod == null && ( ( options & CollectionTraitOptions.AllowNonCollectionEnumerableTypes ) != 0 ) )
			{
				// This should be non collection object isntead of "unappendable" collection.
				result = default( CollectionTraits );
				return false;
			}

			CollectionDetailedKind kind = CollectionDetailedKind.GenericEnumerable;
			if ( genericTypes.IListT != null )
			{
				kind = CollectionDetailedKind.GenericList;
			}
#if !NETFX_35 && !UNITY
			else if ( genericTypes.ISetT != null )
			{
				kind = CollectionDetailedKind.GenericSet;
			}
#endif // !NETFX_35 && !UNITY
			else if ( genericTypes.ICollectionT != null )
			{
				kind = CollectionDetailedKind.GenericCollection;
			}
#if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
			else if ( genericTypes.IReadOnlyListT != null )
			{
				kind = CollectionDetailedKind.GenericReadOnlyList;
			}
			else if ( genericTypes.IReadOnlyCollectionT != null )
			{
				kind = CollectionDetailedKind.GenericReadOnlyCollection;
			}
#endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE )
				
			result =
				new CollectionTraits(
					kind,
					elementType,
					getMethod ?? GetGetEnumeratorMethodFromElementType( source, elementType, options ),
					addMethod,
					GetCountGetterMethod( source, elementType, options )
				);
			return true;
		}
        private PropertiesProcessingResult ProcessProperties(
            TablesStructure tablesStructure,
            Type type,
            Type parentType,
            string parentIdPropertyName,
            string parentIdPropertyTypeName)
        {
            string typeName = type.Name;

            _excludedPropertiesMap.TryGetValue(typeName, out var excludedProperties);
            _idPropertiesMap.TryGetValue(typeName, out var idPropertyName);
            _relationPropertiesMap.TryGetValue(typeName, out var relationPropertyName);
            var valueProperties        = new List <PropertyInfo>();
            var oneChildrenProperties  = new List <(PropertyInfo, Type)>();
            var manyChildrenProperties = new List <(PropertyInfo, Type)>();

            string parentTypeName = parentType?.Name;
            var    collector      = new TableStructure
            {
                TableName = string.IsNullOrWhiteSpace(parentTypeName)
                    ? (string.IsNullOrWhiteSpace(_instanceTag) ? typeName : $"{typeName}_{_instanceTag}")
                    : (string.IsNullOrWhiteSpace(_instanceTag) ? $"{parentTypeName}{typeName}" : $"{parentTypeName}{typeName}_{_instanceTag}"),
                AzureBlobFolder = typeName.ToLower(),
                Columns         = new List <ColumnInfo>(),
            };

            var          topLevelProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            PropertyInfo idProperty         = null;
            PropertyInfo relationProperty   = null;

            foreach (var property in topLevelProperties)
            {
                if (excludedProperties != null && excludedProperties.Contains(property.Name))
                {
                    continue;
                }

                var propertyType = property.PropertyType;

                if ((propertyType.IsClass || propertyType.IsInterface) && propertyType != typeof(string))
                {
                    if (propertyType.IsArray)
                    {
                        manyChildrenProperties.Add((property, propertyType.GetElementType()));
                    }
                    else if (propertyType.IsGenericType && GenericCollectionTypes.Any(t => t == propertyType.GetGenericTypeDefinition()))
                    {
                        var genericType = propertyType.GetGenericArguments()[0];
                        if (genericType.IsClass && genericType != typeof(string))
                        {
                            manyChildrenProperties.Add((property, propertyType.GetGenericArguments()[0]));
                        }
                        else
                        {
                            string genericTypeName  = genericType.IsEnum ? typeof(string).Name : genericType.Name;
                            int    ind              = propertyType.Name.IndexOf('`');
                            var    propertyTypeName = $"{propertyType.Name.Substring(0, ind + 1)}{genericTypeName}";
                            collector.Columns.Add(
                                new ColumnInfo
                            {
                                ColumnName = property.Name,
                                ColumnType = propertyTypeName,
                            });
                            valueProperties.Add(property);
                        }
                    }
                    else
                    {
                        oneChildrenProperties.Add((property, propertyType));
                    }
                }
                else
                {
                    if (idProperty == null && (property.Name == IdPropertyName || property.Name == idPropertyName))
                    {
                        idProperty = property;
                    }
                    else
                    {
                        string propertyTypeName = propertyType.Name;
                        if (propertyType.IsGenericType)
                        {
                            var    genericType     = propertyType.GetGenericArguments()[0];
                            string genericTypeName = genericType.IsEnum ? typeof(string).Name : genericType.Name;
                            int    ind             = propertyTypeName.IndexOf('`');
                            propertyTypeName = $"{propertyTypeName.Substring(0, ind + 1)}{genericTypeName}";
                        }
                        else if (propertyType.IsEnum)
                        {
                            propertyTypeName = typeof(string).Name;
                        }
                        if (property.Name == relationPropertyName)
                        {
                            relationProperty = property;
                        }
                        collector.Columns.Add(
                            new ColumnInfo
                        {
                            ColumnName = property.Name,
                            ColumnType = propertyTypeName,
                        });
                    }
                    valueProperties.Add(property);
                }
            }

            if (collector.Columns.Count > 0)
            {
                if (parentType != type)
                {
                    if (parentIdPropertyName != null)
                    {
                        var parentIdPropertyInChild = type.GetProperty(parentIdPropertyName);
                        if (parentIdPropertyInChild == null)
                        {
                            collector.Columns.Insert(
                                0,
                                new ColumnInfo
                            {
                                ColumnName = parentIdPropertyName,
                                ColumnType = parentIdPropertyTypeName,
                            });
                        }
                    }
                    else if (valueProperties.Count > 0 && parentType != null && PropertiesMap[parentType].ValueProperties.Count > 0)
                    {
                        throw new InvalidOperationException(
                                  $"Type {typeName} must have any identificators that can be used to make relations to its parent type {parentType.Name}");
                    }
                }

                if (idProperty != null)
                {
                    idPropertyName = parentType != null && parentType != type && PropertiesMap[parentType].OneChildrenProperties.Count > 1
                        ? idProperty.Name
                        : IdPropertyName;
                    collector.Columns.Insert(
                        0,
                        new ColumnInfo
                    {
                        ColumnName = idPropertyName,
                        ColumnType = idProperty.PropertyType.Name,
                    });
                }

                tablesStructure.Tables.Add(collector);
            }

            if (!PropertiesMap.ContainsKey(type))
            {
                PropertiesMap.Add(
                    type,
                    new TypeData
                {
                    ValueProperties        = valueProperties,
                    OneChildrenProperties  = oneChildrenProperties.Select(i => i.Item1).ToList(),
                    ManyChildrenProperties = manyChildrenProperties.Select(i => i.Item1).ToList(),
                    ParentIdPropertyName   = parentIdPropertyName,
                });
            }

            return(new PropertiesProcessingResult
            {
                IdProperty = idProperty,
                RelationProperty = relationProperty,
                ValueProperties = valueProperties,
                OneChildrenProperties = oneChildrenProperties,
                ManyChildrenProperties = manyChildrenProperties.Select(i => i.Item2).ToList(),
            });
        }