/// <summary>
        /// Determines whether the type should be handled.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns><c>true</c> if the type should be handled; otherwise, <c>false</c>.</returns>
        protected virtual bool ShouldTypeBeIgnored(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (type == null)
            {
                return(true);
            }

            // Note, although resharper says this isn't possible, it might be
            var fullName = type.GetSafeFullName();

            if (string.IsNullOrWhiteSpace(fullName))
            {
                serializerTypeInfo.AddTypeAsHandled(type);
                return(true);
            }

            // Ignore non-generic .NET
            if (!type.IsGenericTypeEx() && type.GetSafeFullName().StartsWith("System."))
            {
                // Log.Debug("Non-generic .NET system type, can be ignored");
                serializerTypeInfo.AddTypeAsHandled(type);
                return(true);
            }

            if (type.IsCOMObjectEx())
            {
                serializerTypeInfo.AddTypeAsHandled(type);
                return(true);
            }

            return(serializerTypeInfo.ContainsKnownType(type) ||
                   serializerTypeInfo.IsTypeAlreadyHandled(type) ||
                   serializerTypeInfo.IsCollectionAlreadyHandled(type));
        }
        private void AddTypeMembers(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            var typesToCheck = new List <Type>();

            var isModelBase = (type == typeof(ModelBase)) || typeof(ModelBase).IsAssignableFromEx(type);

            if (isModelBase)
            {
                // No need to check members, they will be serialized by ModelBase
                //var catelTypeInfo = PropertyDataManager.Default.GetCatelTypeInfo(type);
                //var modelBaseProperties = catelTypeInfo.GetCatelProperties();
                //foreach (var modelBaseProperty in modelBaseProperties)
                //{
                //    typesToCheck.Add(modelBaseProperty.Value.Type);
                //}
            }
            else
            {
                bool allowNonPublicReflection = AllowNonPublicReflection(type);

                // Fields
                var fields = type.GetFieldsEx(BindingFlagsHelper.GetFinalBindingFlags(false, false, allowNonPublicReflection));
                foreach (var field in fields)
                {
                    typesToCheck.Add(field.FieldType);
                }

                // Properties
                var properties = type.GetPropertiesEx(BindingFlagsHelper.GetFinalBindingFlags(false, false, allowNonPublicReflection));
                foreach (var property in properties)
                {
                    typesToCheck.Add(property.PropertyType);
                }
            }

            foreach (var typeToCheck in typesToCheck)
            {
                if (serializerTypeInfo.IsTypeAlreadyHandled(typeToCheck))
                {
                    continue;
                }

                if (!IsTypeSerializable(typeToCheck, serializerTypeInfo))
                {
                    serializerTypeInfo.AddTypeAsHandled(typeToCheck);
                    continue;
                }

                var propertyTypeFullName = typeToCheck.GetSafeFullName();
                if (propertyTypeFullName == null)
                {
                    serializerTypeInfo.AddTypeAsHandled(typeToCheck);
                    continue;
                }

                GetKnownTypes(typeToCheck, serializerTypeInfo);
            }
        }
        private void AddTypeMembers(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            var isModelBase = (type == typeof(ModelBase)) || typeof(ModelBase).IsAssignableFromEx(type);

            if (isModelBase)
            {
                var catelTypeInfo       = PropertyDataManager.Default.GetCatelTypeInfo(type);
                var modelBaseProperties = catelTypeInfo.GetCatelProperties();
                foreach (var modelBaseProperty in modelBaseProperties)
                {
                    var propertyType = modelBaseProperty.Value.Type;
                    if (propertyType.FullName != null)
                    {
                        GetKnownTypes(propertyType, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(propertyType);
                    }
                }
            }
            else
            {
                bool allowNonPublicReflection = AllowNonPublicReflection(type);

                // Fields
                var fields = type.GetFieldsEx(BindingFlagsHelper.GetFinalBindingFlags(false, false, allowNonPublicReflection));
                foreach (var field in fields)
                {
                    var fieldType = field.FieldType;
                    if (fieldType.FullName != null)
                    {
                        GetKnownTypes(fieldType, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(fieldType);
                    }
                }

                // Properties
                var properties = type.GetPropertiesEx(BindingFlagsHelper.GetFinalBindingFlags(false, false, allowNonPublicReflection));
                foreach (var property in properties)
                {
                    var propertyType = property.PropertyType;
                    if (propertyType.FullName != null)
                    {
                        GetKnownTypes(propertyType, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(propertyType);
                    }
                }
            }
        }
Example #4
0
        /// <summary>
        /// Determines whether the type should be handled.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns><c>true</c> if the type should be handled; otherwise, <c>false</c>.</returns>
        protected virtual bool ShouldTypeBeIgnored(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (type == null)
            {
                return(true);
            }

            // Never include generic type definitions, otherwise we will get this:
            // Error while getting known types for Type 'Catel.Tests.Data.PropertyDataManagerFacts+SupportsGenericClasses+GenericClass`1[T]'. The type must not be an open or partial generic class.
            if (type.IsGenericTypeDefinitionEx())
            {
                return(true);
            }

            // Note, although resharper says this isn't possible, it might be
            var fullName = type.GetSafeFullName(false);

            if (string.IsNullOrWhiteSpace(fullName))
            {
                serializerTypeInfo.AddTypeAsHandled(type);
                return(true);
            }

            // Ignore non-generic .NET
            if (!type.IsGenericTypeEx() && fullName.StartsWith("System."))
            {
                // Log.Debug("Non-generic .NET system type, can be ignored");
                serializerTypeInfo.AddTypeAsHandled(type);
                return(true);
            }

            if (type.IsCOMObjectEx())
            {
                serializerTypeInfo.AddTypeAsHandled(type);
                return(true);
            }

            return(serializerTypeInfo.ContainsKnownType(type) ||
                   serializerTypeInfo.IsTypeAlreadyHandled(type) ||
                   serializerTypeInfo.IsCollectionAlreadyHandled(type));
        }
        /// <summary>
        /// Determines whether the type should be handled.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns><c>true</c> if the type should be handled; otherwise, <c>false</c>.</returns>
        protected virtual bool ShouldTypeBeIgnored(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (type == null)
            {
                return true;
            }

            // Never include generic type definitions, otherwise we will get this:
            // Error while getting known types for Type 'Catel.Test.Data.PropertyDataManagerFacts+SupportsGenericClasses+GenericClass`1[T]'. The type must not be an open or partial generic class.
            if (type.IsGenericTypeDefinitionEx())
            {
                return true;
            }

            // Note, although resharper says this isn't possible, it might be
            var fullName = type.GetSafeFullName();
            if (string.IsNullOrWhiteSpace(fullName))
            {
                serializerTypeInfo.AddTypeAsHandled(type);
                return true;
            }

            // Ignore non-generic .NET
            if (!type.IsGenericTypeEx() && fullName.StartsWith("System."))
            {
                // Log.Debug("Non-generic .NET system type, can be ignored");
                serializerTypeInfo.AddTypeAsHandled(type);
                return true;
            }

            if (type.IsCOMObjectEx())
            {
                serializerTypeInfo.AddTypeAsHandled(type);
                return true;
            }

            return serializerTypeInfo.ContainsKnownType(type) ||
                   serializerTypeInfo.IsTypeAlreadyHandled(type) ||
                   serializerTypeInfo.IsCollectionAlreadyHandled(type);
        }
        private void AddTypeMembers(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            var typesToCheck = new List<Type>();

            var isModelBase = type.IsModelBase();
            if (isModelBase)
            {
                // No need to check members, they will be serialized by ModelBase
                //var catelTypeInfo = PropertyDataManager.Default.GetCatelTypeInfo(type);
                //var modelBaseProperties = catelTypeInfo.GetCatelProperties();
                //foreach (var modelBaseProperty in modelBaseProperties)
                //{
                //    typesToCheck.Add(modelBaseProperty.Value.Type);
                //}
            }
            else
            {
                var allowNonPublicReflection = AllowNonPublicReflection(type);

                // Fields
                var fields = type.GetFieldsEx(BindingFlagsHelper.GetFinalBindingFlags(false, false, allowNonPublicReflection));
                foreach (var field in fields)
                {
                    typesToCheck.Add(field.FieldType);
                }

                // Properties
                var properties = type.GetPropertiesEx(BindingFlagsHelper.GetFinalBindingFlags(false, false, allowNonPublicReflection));
                foreach (var property in properties)
                {
                    typesToCheck.Add(property.PropertyType);
                }
            }

            foreach (var typeToCheck in typesToCheck)
            {
                if (serializerTypeInfo.IsTypeAlreadyHandled(typeToCheck))
                {
                    continue;
                }

                if (!IsTypeSerializable(typeToCheck, serializerTypeInfo))
                {
                    serializerTypeInfo.AddTypeAsHandled(typeToCheck);
                    continue;
                }

                var propertyTypeFullName = typeToCheck.GetSafeFullName();
                if (propertyTypeFullName == null)
                {
                    serializerTypeInfo.AddTypeAsHandled(typeToCheck);
                    continue;
                }

                GetKnownTypes(typeToCheck, serializerTypeInfo);
            }
        }
        /// <summary>
        /// Gets the known types inside the specific type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <param name="resolveAbstractClassesAndInterfaces">if set to <c>true</c> [resolve abstract classes and interfaces].</param>
        /// <returns>Array of <see cref="Type" /> that are found in the object type.</returns>
        protected virtual void GetKnownTypes(Type type, XmlSerializerTypeInfo serializerTypeInfo, bool resolveAbstractClassesAndInterfaces = true)
        {
            if (ShouldTypeBeIgnored(type, serializerTypeInfo))
            {
                return;
            }

#if ENABLE_DETAILED_LOGGING
            Log.Debug("Getting known types for '{0}'", type.GetSafeFullName());
#endif

            GetKnownTypesForItems(type, serializerTypeInfo);

            // If this is an interface or abstract, we need to retieve all items that might possible implement or derive
            var isInterface = type.IsInterfaceEx();
            var isAbstract = type.IsAbstractEx();
            if (isInterface || isAbstract)
            {
                if (!serializerTypeInfo.IsTypeAlreadyHandled(type) && resolveAbstractClassesAndInterfaces)
                {
                    // Interfaces / abstract classes are not a type, and in fact a LOT of types can be added (in fact every object implementing 
                    // the interface). For serialization, this is not a problem (we know the exact type), but for deserialization this IS an 
                    // issue because we should expect EVERY type that implements the type in the whole AppDomain.
                    // This is huge performance hit, but it's the cost for dynamic easy on-the-fly serialization in WPF and Silverlight. Luckily
                    // we already implemented caching.

                    // Don't check this type again in children checks
                    serializerTypeInfo.AddTypeAsHandled(type);

#if ENABLE_DETAILED_LOGGING
                    Log.Debug("Type is an interface / abstract class, checking all types implementing / deriving");
#endif

                    if (isInterface)
                    {
                        var typesImplementingInterface = TypeCache.GetTypesImplementingInterface(type);
                        foreach (var typeImplementingInterface in typesImplementingInterface)
                        {
                            if (typeImplementingInterface != type)
                            {
                                GetKnownTypes(typeImplementingInterface, serializerTypeInfo);
                            }
                        }
                    }

                    if (isAbstract)
                    {
                        var typesDerivingFromClass = TypeCache.GetTypes(type.IsAssignableFromEx);
                        foreach (var typeDerivingFromClass in typesDerivingFromClass)
                        {
                            if (typeDerivingFromClass != type)
                            {
                                GetKnownTypes(typeDerivingFromClass, serializerTypeInfo);
                            }
                        }
                    }

#if ENABLE_DETAILED_LOGGING
                    Log.Debug("Finished checking all types implementing / deriving");
#endif
                }

                // The interface itself is ignored
                return;
            }

            if (serializerTypeInfo.IsSpecialCollectionType(type) && !type.IsInterfaceEx())
            {
#if ENABLE_DETAILED_LOGGING
                Log.Debug("Type is a special collection type, adding it to the array of known types");
#endif

                AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo);
            }

            // Fix generics
            if (type.GetSafeFullName().StartsWith("System."))
            {
                var genericArguments = type.GetGenericArgumentsEx();
                foreach (var genericArgument in genericArguments)
                {
#if ENABLE_DETAILED_LOGGING
                    Log.Debug("Retrieving known types for generic argument '{0}' of '{1}'", genericArgument.GetSafeFullName(), type.GetSafeFullName());
#endif

                    GetKnownTypes(genericArgument, serializerTypeInfo);
                }

                return;
            }

            if (!AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo))
            {
                serializerTypeInfo.AddTypeAsHandled(type);
            }

            AddTypeMembers(type, serializerTypeInfo);

            // If this isn't the base type, check that as well
            var baseType = type.GetBaseTypeEx();
            if (baseType != null)
            {
#if ENABLE_DETAILED_LOGGING
                Log.Debug("Checking base type of '{0}' for known types", type.GetSafeFullName());
#endif

                if (baseType.FullName != null)
                {
                    GetKnownTypes(baseType, serializerTypeInfo);
                }
                else
                {
                    serializerTypeInfo.AddTypeAsHandled(baseType);
                }
            }

            // Last but not least, check if the type is decorated with KnownTypeAttributes
            var knowTypesByAttributes = GetKnownTypesViaAttributes(type);
            if (knowTypesByAttributes.Length > 0)
            {
#if ENABLE_DETAILED_LOGGING
                Log.Debug("Found {0} additional known types for type '{1}'", knowTypesByAttributes.Length, type.GetSafeFullName());
#endif

                foreach (var knownTypeByAttribute in knowTypesByAttributes)
                {
                    var attributeType = knownTypeByAttribute;
                    var attributeTypeFullName = attributeType.GetSafeFullName();
                    if (attributeTypeFullName != null)
                    {
                        GetKnownTypes(knownTypeByAttribute, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(attributeType);
                    }
                }
            }
        }
        /// <summary>
        /// Determines whether the type should be handled.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns><c>true</c> if the type should be handled; otherwise, <c>false</c>.</returns>
        protected virtual bool ShouldTypeBeIgnored(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (type == null)
            {
                return true;
            }

            // Note, although resharper says this isn't possible, it might be
            if (type.FullName == null)
            {
                serializerTypeInfo.AddTypeAsHandled(type);
                return true;
            }

            // Ignore non-generic .NET
            if (!type.IsGenericTypeEx() && type.GetSafeFullName().StartsWith("System."))
            {
                // Log.Debug("Non-generic .NET system type, can be ignored");
                serializerTypeInfo.AddTypeAsHandled(type);
                return true;
            }

            return serializerTypeInfo.ContainsKnownType(type) || serializerTypeInfo.IsTypeAlreadyHandled(type);
        }
        private void AddTypeMembers(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            var isModelBase = (type == typeof(ModelBase)) || typeof(ModelBase).IsAssignableFromEx(type);
            if (isModelBase)
            {
                var catelTypeInfo = PropertyDataManager.Default.GetCatelTypeInfo(type);
                var modelBaseProperties = catelTypeInfo.GetCatelProperties();
                foreach (var modelBaseProperty in modelBaseProperties)
                {
                    var propertyType = modelBaseProperty.Value.Type;
                    if (propertyType.FullName != null)
                    {
                        GetKnownTypes(propertyType, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(propertyType);
                    }
                }
            }
            else
            {
                bool allowNonPublicReflection = AllowNonPublicReflection(type);

                // Fields
                var fields = type.GetFieldsEx(BindingFlagsHelper.GetFinalBindingFlags(false, false, allowNonPublicReflection));
                foreach (var field in fields)
                {
                    var fieldType = field.FieldType;
                    if (fieldType.FullName != null)
                    {
                        GetKnownTypes(fieldType, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(fieldType);
                    }
                }

                // Properties
                var properties = type.GetPropertiesEx(BindingFlagsHelper.GetFinalBindingFlags(false, false, allowNonPublicReflection));
                foreach (var property in properties)
                {
                    var propertyType = property.PropertyType;
                    if (propertyType.FullName != null)
                    {
                        GetKnownTypes(propertyType, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(propertyType);
                    }
                }
            }
        }
        /// <summary>
        /// Gets the known types inside the specific type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns>Array of <see cref="Type"/> that are found in the object type.</returns>
        protected virtual void GetKnownTypes(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (ShouldTypeBeIgnored(type, serializerTypeInfo))
            {
                return;
            }

            Log.Debug("Getting known types for '{0}'", type.GetSafeFullName());

            // If this is an interface, HOUSTON, WE HAVE A PROBLEM
            if (type.IsInterfaceEx())
            {
                if (!serializerTypeInfo.IsTypeAlreadyHandled(type))
                {
                    Log.Debug("Type is an interface, checking all types deriving from this interface");

                    // Don't check this interface again in children checks
                    serializerTypeInfo.AddTypeAsHandled(type);

                    // Interfaces are not a type, and in fact a LOT of types can be added (in fact every object implementing the interface). For
                    // serialization, this is not a problem (we know the exact type), but for deserialization this IS an issue because we should
                    // expect EVERY type that implements the type in the whole AppDomain.
                    // This is huge performance hit, but it's the cost for dynamic easy on-the-fly serialization in WPF and Silverlight. Luckily
                    // we already implemented caching.
                    var typesDerivingFromInterface = TypeCache.GetTypes(t => t.ImplementsInterfaceEx(type));
                    foreach (var typeDerivingFromInterface in typesDerivingFromInterface)
                    {
                        if (typeDerivingFromInterface != type)
                        {
                            GetKnownTypes(typeDerivingFromInterface, serializerTypeInfo);
                        }
                    }

                    Log.Debug("Finished checking all types deriving from this interface");
                }

                // The interface itself is ignored
                return;
            }

            if (serializerTypeInfo.IsSpecialCollectionType(type) && !type.IsInterfaceEx())
            {
                Log.Debug("Type is a special collection type, adding it to the array of known types");

                AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo);
            }

            // Fix generics
            if (type.GetSafeFullName().StartsWith("System."))
            {
                var genericArguments = type.GetGenericArgumentsEx();
                foreach (var genericArgument in genericArguments)
                {
                    Log.Debug("Retrieving known types for generic argument '{0}' of '{1}'", genericArgument.GetSafeFullName(), type.GetSafeFullName());

                    GetKnownTypes(genericArgument, serializerTypeInfo);
                }

                return;
            }

            if (!AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo))
            {
                serializerTypeInfo.AddTypeAsHandled(type);
            }

            AddTypeMembers(type, serializerTypeInfo);

            // If this isn't the base type, check that as well
            var baseType = type.GetBaseTypeEx();
            if (baseType != null)
            {
                Log.Debug("Checking base type of '{0}' for known types", type.GetSafeFullName());

                if (baseType.FullName != null)
                {
                    GetKnownTypes(baseType, serializerTypeInfo);
                }
                else
                {
                    serializerTypeInfo.AddTypeAsHandled(baseType);
                }
            }

            // Last but not least, check if the type is decorated with KnownTypeAttributes
            var knowTypesByAttributes = GetKnownTypesViaAttributes(type);
            if (knowTypesByAttributes.Length > 0)
            {
                Log.Debug("Found {0} additional known types for type '{1}'", knowTypesByAttributes.Length, type.GetSafeFullName());

                foreach (var knownTypeByAttribute in knowTypesByAttributes)
                {
                    var attributeType = knownTypeByAttribute;
                    if (attributeType.FullName != null)
                    {
                        GetKnownTypes(knownTypeByAttribute, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(attributeType);
                    }
                }
            }
        }
        /// <summary>
        /// Gets the known types inside the specific type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns>Array of <see cref="Type"/> that are found in the object type.</returns>
        protected virtual void GetKnownTypes(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (ShouldTypeBeIgnored(type, serializerTypeInfo))
            {
                return;
            }

            Log.Debug("Getting known types for '{0}'", type.GetSafeFullName());

            GetKnownTypesForItems(type, serializerTypeInfo);

            // If this is an interface or abstract, we need to retieve all items that might possible implement or derive
            bool isInterface = type.IsInterfaceEx();
            bool isAbstract  = type.IsAbstractEx();

            if (isInterface || isAbstract)
            {
                if (!serializerTypeInfo.IsTypeAlreadyHandled(type))
                {
                    // Interfaces / abstract classes are not a type, and in fact a LOT of types can be added (in fact every object implementing
                    // the interface). For serialization, this is not a problem (we know the exact type), but for deserialization this IS an
                    // issue because we should expect EVERY type that implements the type in the whole AppDomain.
                    // This is huge performance hit, but it's the cost for dynamic easy on-the-fly serialization in WPF and Silverlight. Luckily
                    // we already implemented caching.

                    // Don't check this type again in children checks
                    serializerTypeInfo.AddTypeAsHandled(type);

                    Log.Debug("Type is an interface / abstract class, checking all types implementing / deriving");

                    if (isInterface)
                    {
                        var typesImplementingInterface = TypeCache.GetTypesImplementingInterface(type);
                        //var typesImplementingInterface = TypeCache.GetTypes(t => t.ImplementsInterfaceEx(type));
                        foreach (var typeImplementingInterface in typesImplementingInterface)
                        {
                            if (typeImplementingInterface != type)
                            {
                                GetKnownTypes(typeImplementingInterface, serializerTypeInfo);
                            }
                        }
                    }

                    if (isAbstract)
                    {
                        var typesDerivingFromClass = TypeCache.GetTypes(type.IsAssignableFromEx);
                        foreach (var typeDerivingFromClass in typesDerivingFromClass)
                        {
                            if (typeDerivingFromClass != type)
                            {
                                GetKnownTypes(typeDerivingFromClass, serializerTypeInfo);
                            }
                        }
                    }

                    Log.Debug("Finished checking all types implementing / deriving");
                }

                // The interface itself is ignored
                return;
            }

            if (serializerTypeInfo.IsSpecialCollectionType(type) && !type.IsInterfaceEx())
            {
                Log.Debug("Type is a special collection type, adding it to the array of known types");

                AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo);
            }

            // Fix generics
            if (type.GetSafeFullName().StartsWith("System."))
            {
                var genericArguments = type.GetGenericArgumentsEx();
                foreach (var genericArgument in genericArguments)
                {
                    Log.Debug("Retrieving known types for generic argument '{0}' of '{1}'", genericArgument.GetSafeFullName(), type.GetSafeFullName());

                    GetKnownTypes(genericArgument, serializerTypeInfo);
                }

                return;
            }

            if (!AddTypeToKnownTypesIfSerializable(type, serializerTypeInfo))
            {
                serializerTypeInfo.AddTypeAsHandled(type);
            }

            AddTypeMembers(type, serializerTypeInfo);

            // If this isn't the base type, check that as well
            var baseType = type.GetBaseTypeEx();

            if (baseType != null)
            {
                Log.Debug("Checking base type of '{0}' for known types", type.GetSafeFullName());

                if (baseType.FullName != null)
                {
                    GetKnownTypes(baseType, serializerTypeInfo);
                }
                else
                {
                    serializerTypeInfo.AddTypeAsHandled(baseType);
                }
            }

            // Last but not least, check if the type is decorated with KnownTypeAttributes
            var knowTypesByAttributes = GetKnownTypesViaAttributes(type);

            if (knowTypesByAttributes.Length > 0)
            {
                Log.Debug("Found {0} additional known types for type '{1}'", knowTypesByAttributes.Length, type.GetSafeFullName());

                foreach (var knownTypeByAttribute in knowTypesByAttributes)
                {
                    var attributeType         = knownTypeByAttribute;
                    var attributeTypeFullName = attributeType.GetSafeFullName();
                    if (attributeTypeFullName != null)
                    {
                        GetKnownTypes(knownTypeByAttribute, serializerTypeInfo);
                    }
                    else
                    {
                        serializerTypeInfo.AddTypeAsHandled(attributeType);
                    }
                }
            }
        }