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 static MethodInfo GetAddMethod(Type targetType, Type argumentType, CollectionTraitOptions options) { if ((options | CollectionTraitOptions.WithAddMethod) == 0) { return(null); } var argumentTypes = new[] { argumentType }; var typedAdd = targetType.GetMethod("Add", argumentTypes); if (typedAdd != null) { return(typedAdd); } var icollectionT = typeof(ICollection <>).MakeGenericType(argumentType); if (targetType.IsAssignableTo(icollectionT)) { return(icollectionT.GetMethod("Add", argumentTypes)); } // It ensures .NET Framework and .NET Core compatibility and provides "natural" feel. var objectAdd = targetType.GetMethod("Add", ObjectAddParameterTypes); if (objectAdd != null) { return(objectAdd); } if (targetType.IsAssignableTo(typeof(IList))) { return(typeof(IList).GetMethod("Add", ObjectAddParameterTypes)); } return(null); }
private static MethodInfo GetGetEnumeratorMethodFromEnumerableType(Type targetType, Type enumerableType, CollectionTraitOptions options) { if ((options | CollectionTraitOptions.WithGetEnumeratorMethod) == 0) { return(null); } return(FindInterfaceMethod(targetType, enumerableType, "GetEnumerator", ReflectionAbstractions.EmptyTypes)); }
private static MethodInfo GetGetEnumeratorMethodFromElementType(Type targetType, Type elementType, CollectionTraitOptions options) { if ((options | CollectionTraitOptions.WithGetEnumeratorMethod) == 0) { return(null); } return(FindInterfaceMethod(targetType, typeof(IEnumerable <>).MakeGenericType(elementType), "GetEnumerator", ReflectionAbstractions.EmptyTypes)); }
private static bool TryCreateGenericCollectionTraits(Type source, Type type, CollectionTraitOptions options, out CollectionTraits result) { if (type == typeof(IDictionary <MessagePackObject, MessagePackObject>) #if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE) || type == typeof(IReadOnlyDictionary <MessagePackObject, MessagePackObject>) #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) ) { result = new CollectionTraits( #if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE) (source == typeof(IDictionary <MessagePackObject, MessagePackObject>) || source.Implements(typeof(IDictionary <MessagePackObject, MessagePackObject>))) ? CollectionDetailedKind.GenericDictionary : CollectionDetailedKind.GenericReadOnlyDictionary, #else CollectionDetailedKind.GenericDictionary, #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) typeof(KeyValuePair <MessagePackObject, MessagePackObject>), GetGetEnumeratorMethodFromEnumerableType(source, typeof(IEnumerable <KeyValuePair <MessagePackObject, MessagePackObject> >), options), GetAddMethod(source, typeof(MessagePackObject), typeof(MessagePackObject), options), GetCountGetterMethod(source, typeof(KeyValuePair <MessagePackObject, MessagePackObject>), options) ); return(true); } if (type == typeof(IEnumerable <MessagePackObject>)) { var addMethod = GetAddMethod(source, typeof(MessagePackObject), options | CollectionTraitOptions.WithAddMethod); if (addMethod != null) { { result = new CollectionTraits( (source == typeof(IList <MessagePackObject>) || source.Implements(typeof(IList <MessagePackObject>))) ? CollectionDetailedKind.GenericList #if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE) : (source == typeof(IReadOnlyList <MessagePackObject>) || source.Implements(typeof(IReadOnlyList <MessagePackObject>))) ? CollectionDetailedKind.GenericReadOnlyList #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) #if !NETFX_35 && !UNITY : (source == typeof(ISet <MessagePackObject>) || source.Implements(typeof(ISet <MessagePackObject>))) ? CollectionDetailedKind.GenericSet #endif // !NETFX_35 && !UNITY : (source == typeof(ICollection <MessagePackObject>) || source.Implements(typeof(ICollection <MessagePackObject>))) ? CollectionDetailedKind.GenericCollection #if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE) : (source == typeof(IReadOnlyCollection <MessagePackObject>) || source.Implements(typeof(IReadOnlyCollection <MessagePackObject>))) ? CollectionDetailedKind.GenericReadOnlyCollection #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) : CollectionDetailedKind.GenericEnumerable, typeof(MessagePackObject), GetGetEnumeratorMethodFromEnumerableType(source, typeof(IEnumerable <MessagePackObject>), options), addMethod, GetCountGetterMethod(source, typeof(MessagePackObject), options) ); return(true); } } } result = default(CollectionTraits); return(false); }
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 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 MethodInfo GetCountGetterMethod( Type targetType, Type elementType, CollectionTraitOptions options ) // ReSharper restore UnusedParameter.Local { #if !UNITY // get_Count is not used other than Unity. return null; #else if ( ( options | CollectionTraitOptions.WithCountPropertyGetter ) == 0 ) { return null; } var result = targetType.GetProperty( "Count" ); if ( result != null && result.GetHasPublicGetter() ) { return result.GetGetMethod(); } var icollectionT = typeof( ICollection<> ).MakeGenericType( elementType ); if ( targetType.IsAssignableTo( icollectionT ) ) { return icollectionT.GetProperty( "Count" ).GetGetMethod(); } #if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) var ireadOnlyCollectionT = typeof( IReadOnlyCollection<> ).MakeGenericType( elementType ); if ( targetType.IsAssignableTo( ireadOnlyCollectionT ) ) { return ireadOnlyCollectionT.GetProperty( "Count" ).GetGetMethod(); } #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) if ( targetType.IsAssignableTo( typeof( ICollection ) ) ) { return typeof( ICollection ).GetProperty( "Count" ).GetGetMethod(); } return null; #endif // !UNITY }
private static MethodInfo GetAddMethod( Type targetType, Type keyType, Type valueType, CollectionTraitOptions options ) { if ( ( options | CollectionTraitOptions.WithAddMethod ) == 0 ) { return null; } var argumentTypes = new[] { keyType, valueType }; var result = targetType.GetMethod( "Add", argumentTypes ); if ( result != null ) { return result; } return typeof( IDictionary<,> ).MakeGenericType( argumentTypes ).GetMethod( "Add", argumentTypes ); }
private static MethodInfo GetGetEnumeratorMethodFromEnumerableType( Type targetType, Type enumerableType, CollectionTraitOptions options ) { if ( ( options | CollectionTraitOptions.WithGetEnumeratorMethod ) == 0 ) { return null; } return FindInterfaceMethod( targetType, enumerableType, "GetEnumerator", ReflectionAbstractions.EmptyTypes ); }
private static MethodInfo GetAddMethod( Type targetType, Type argumentType, CollectionTraitOptions options ) { if ( ( options | CollectionTraitOptions.WithAddMethod ) == 0 ) { return null; } var argumentTypes = new[] { argumentType }; var typedAdd = targetType.GetMethod( "Add", argumentTypes ); if ( typedAdd != null ) { return typedAdd; } var icollectionT = typeof( ICollection<> ).MakeGenericType( argumentType ); if ( targetType.IsAssignableTo( icollectionT ) ) { return icollectionT.GetMethod( "Add", argumentTypes ); } // It ensures .NET Framework and .NET Core compatibility and provides "natural" feel. var objectAdd = targetType.GetMethod( "Add", ObjectAddParameterTypes ); if ( objectAdd != null ) { return objectAdd; } if ( targetType.IsAssignableTo( typeof( IList ) ) ) { return typeof( IList ).GetMethod( "Add", ObjectAddParameterTypes ); } return null; }
private static MethodInfo GetGetEnumeratorMethodFromElementType( Type targetType, Type elementType, CollectionTraitOptions options ) { if ( ( options | CollectionTraitOptions.WithGetEnumeratorMethod ) == 0 ) { return null; } return FindInterfaceMethod( targetType, typeof( IEnumerable<> ).MakeGenericType( elementType ), "GetEnumerator", ReflectionAbstractions.EmptyTypes ); }
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 TryCreateGenericCollectionTraits( Type source, Type type, CollectionTraitOptions options, out CollectionTraits result ) { if ( type == typeof( IDictionary<MessagePackObject, MessagePackObject> ) #if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) || type == typeof( IReadOnlyDictionary<MessagePackObject, MessagePackObject> ) #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) ) { result = new CollectionTraits( #if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) ( source == typeof( IDictionary<MessagePackObject, MessagePackObject> ) || source.Implements( typeof( IDictionary<MessagePackObject, MessagePackObject> ) ) ) ? CollectionDetailedKind.GenericDictionary : CollectionDetailedKind.GenericReadOnlyDictionary, #else CollectionDetailedKind.GenericDictionary, #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) typeof( KeyValuePair<MessagePackObject, MessagePackObject> ), GetGetEnumeratorMethodFromEnumerableType( source, typeof( IEnumerable<KeyValuePair<MessagePackObject, MessagePackObject>> ), options ), GetAddMethod( source, typeof( MessagePackObject ), typeof( MessagePackObject ), options ), GetCountGetterMethod( source, typeof( KeyValuePair<MessagePackObject, MessagePackObject> ), options ) ); return true; } if ( type == typeof( IEnumerable<MessagePackObject> ) ) { var addMethod = GetAddMethod( source, typeof( MessagePackObject ), options | CollectionTraitOptions.WithAddMethod ); if ( addMethod != null ) { { result = new CollectionTraits( ( source == typeof( IList<MessagePackObject> ) || source.Implements( typeof( IList<MessagePackObject> ) ) ) ? CollectionDetailedKind.GenericList #if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) : ( source == typeof( IReadOnlyList<MessagePackObject> ) || source.Implements( typeof( IReadOnlyList<MessagePackObject> ) ) ) ? CollectionDetailedKind.GenericReadOnlyList #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) #if !NETFX_35 && !UNITY : ( source == typeof( ISet<MessagePackObject> ) || source.Implements( typeof( ISet<MessagePackObject> ) ) ) ? CollectionDetailedKind.GenericSet #endif // !NETFX_35 && !UNITY : ( source == typeof( ICollection<MessagePackObject> ) || source.Implements( typeof( ICollection<MessagePackObject> ) ) ) ? CollectionDetailedKind.GenericCollection #if !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) : ( source == typeof( IReadOnlyCollection<MessagePackObject> ) || source.Implements( typeof( IReadOnlyCollection<MessagePackObject> ) ) ) ? CollectionDetailedKind.GenericReadOnlyCollection #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) : CollectionDetailedKind.GenericEnumerable, typeof( MessagePackObject ), GetGetEnumeratorMethodFromEnumerableType( source, typeof( IEnumerable<MessagePackObject> ), options ), addMethod, GetCountGetterMethod( source, typeof( MessagePackObject ), options ) ); return true; } } } result = default( CollectionTraits ); return false; }
private static MethodInfo GetCountGetterMethod(Type targetType, Type elementType, CollectionTraitOptions options) // ReSharper restore UnusedParameter.Local { #if !UNITY // get_Count is not used other than Unity. return(null); #else if ((options | CollectionTraitOptions.WithCountPropertyGetter) == 0) { return(null); } var result = targetType.GetProperty("Count"); if (result != null && result.GetHasPublicGetter()) { return(result.GetGetMethod()); } var icollectionT = typeof(ICollection <>).MakeGenericType(elementType); if (targetType.IsAssignableTo(icollectionT)) { return(icollectionT.GetProperty("Count").GetGetMethod()); } #if !NETFX_35 && !UNITY && !NETFX_40 && !(SILVERLIGHT && !WINDOWS_PHONE) var ireadOnlyCollectionT = typeof(IReadOnlyCollection <>).MakeGenericType(elementType); if (targetType.IsAssignableTo(ireadOnlyCollectionT)) { return(ireadOnlyCollectionT.GetProperty("Count").GetGetMethod()); } #endif // !NETFX_35 && !UNITY && !NETFX_40 && !( SILVERLIGHT && !WINDOWS_PHONE ) if (targetType.IsAssignableTo(typeof(ICollection))) { return(typeof(ICollection).GetProperty("Count").GetGetMethod()); } return(null); #endif // !UNITY }
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 MethodInfo GetAddMethod(Type targetType, Type keyType, Type valueType, CollectionTraitOptions options) { if ((options | CollectionTraitOptions.WithAddMethod) == 0) { return(null); } var argumentTypes = new[] { keyType, valueType }; var result = targetType.GetMethod("Add", argumentTypes); if (result != null) { return(result); } return(typeof(IDictionary <,>).MakeGenericType(argumentTypes).GetMethod("Add", argumentTypes)); }
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; }