Ejemplo n.º 1
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);
            }

            // 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));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets the Data Contract serializer for a specific type. This method caches serializers so the
        /// performance can be improved when a serializer is used more than once.
        /// </summary>
        /// <param name="serializingType">The type that is currently (de)serializing.</param>
        /// <param name="typeToSerialize">The type to (de)serialize.</param>
        /// <param name="xmlName">Name of the property as known in XML.</param>
        /// <param name="rootNamespace">The root namespace.</param>
        /// <param name="additionalKnownTypes">A list of additional types to add to the known types.</param>
        /// <returns><see cref="DataContractSerializer" /> for the given type.</returns>
        /// <exception cref="ArgumentNullException">The <paramref name="serializingType" /> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">The <paramref name="typeToSerialize" /> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">The <paramref name="xmlName" /> is <c>null</c> or whitespace.</exception>
        public virtual DataContractSerializer GetDataContractSerializer(Type serializingType, Type typeToSerialize, string xmlName, string rootNamespace = null, List <Type> additionalKnownTypes = null)
        {
            Argument.IsNotNull("serializingType", serializingType);
            Argument.IsNotNull("typeToSerialize", typeToSerialize);
            Argument.IsNotNullOrWhitespace("xmlName", xmlName);

            string key = string.Format("{0}|{1}", typeToSerialize.GetSafeFullName(), xmlName);

            return(_dataContractSerializersCache.GetFromCacheOrFetch(key, () =>
            {
                Log.Debug("Getting known types for xml serialization of '{0}'", typeToSerialize.GetSafeFullName());

                var serializerTypeInfo = new XmlSerializerTypeInfo(serializingType, typeToSerialize, additionalKnownTypes);

                GetKnownTypes(typeToSerialize, serializerTypeInfo);

                var knownTypesViaAttributes = GetKnownTypesViaAttributes(serializingType);
                foreach (var knownTypeViaAttribute in knownTypesViaAttributes)
                {
                    GetKnownTypes(knownTypeViaAttribute, serializerTypeInfo);
                }

                if (additionalKnownTypes != null)
                {
                    foreach (var additionalKnownType in additionalKnownTypes)
                    {
                        GetKnownTypes(additionalKnownType, serializerTypeInfo);
                    }
                }

                var xmlSerializer = new DataContractSerializer(typeToSerialize, xmlName, rootNamespace ?? string.Empty, serializerTypeInfo.KnownTypes);
                return xmlSerializer;
            }));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Adds the type to the known types if the type is serializable.
        /// </summary>
        /// <param name="typeToAdd">The type to add.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns><c>true</c> if the type is serializable; otherwise <c>false</c>.</returns>
        protected virtual bool AddTypeToKnownTypesIfSerializable(Type typeToAdd, XmlSerializerTypeInfo serializerTypeInfo)
        {
            // Collection first, this collection of types is smaller so if we have a hit, we exit sooner
            if (serializerTypeInfo.IsCollectionAlreadyHandled(typeToAdd))
            {
                return(true);
            }

            if (serializerTypeInfo.ContainsKnownType(typeToAdd))
            {
                return(true);
            }

            serializerTypeInfo.AddCollectionAsHandled(typeToAdd);

            // If this is a special collection type (generic), then we need to make sure that if the inner type is
            // an interface, we do not add it again if already added.
            // See this issue http://catel.codeplex.com/workitem/7167
            if (serializerTypeInfo.IsSpecialCollectionType(typeToAdd))
            {
                // Always ignore
                return(false);
            }

            return(serializerTypeInfo.AddKnownType(typeToAdd));
        }
Ejemplo n.º 4
0
        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);
                    }
                }
            }
        }
Ejemplo n.º 6
0
 /// <summary>
 /// Gets the known types of IEnumerable 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>
 private void GetKnownTypesForItems(Type type, XmlSerializerTypeInfo serializerTypeInfo)
 {
     if (type.ImplementsInterfaceEx <IEnumerable>())
     {
         foreach (var argument in type.GetGenericArgumentsEx())
         {
             GetKnownTypes(argument, serializerTypeInfo);
         }
     }
 }
Ejemplo n.º 7
0
        private void GetKnownTypesForItemsInstance(object obj, XmlSerializerTypeInfo serializerTypeInfo)
        {
            var ienumerable = obj as IEnumerable;

            if (ienumerable != null)
            {
                foreach (var item in ienumerable)
                {
                    GetKnownTypesForInstance(item, serializerTypeInfo);
                }
            }
        }
        /// <summary>
        /// Adds the type to the known types if the type is serializable.
        /// </summary>
        /// <param name="typeToAdd">The type to add.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns><c>true</c> if the type is serializable; otherwise <c>false</c>.</returns>
        protected virtual bool AddTypeToKnownTypesIfSerializable(Type typeToAdd, XmlSerializerTypeInfo serializerTypeInfo)
        {
            // Collection first, this collection of types is smaller so if we have a hit, we exit sooner
            if (serializerTypeInfo.IsCollectionAlreadyHandled(typeToAdd))
            {
                return(true);
            }

            if (serializerTypeInfo.ContainsKnownType(typeToAdd))
            {
                return(true);
            }

            serializerTypeInfo.AddCollectionAsHandled(typeToAdd);

            // If this is a special collection type (generic), then we need to make sure that if the inner type is
            // an interface, we do not add it again if already added.
            // See this issue http://catel.codeplex.com/workitem/7167
            if (serializerTypeInfo.IsSpecialCollectionType(typeToAdd))
            {
                // Always ignore as a test
                return(false);

                // TODO: Also check interfaces
                //    // It might be a base type, loop all
                //    var baseType = typeToAdd;
                //    while (baseType != null)
                //    {
                //        if (baseType.IsGenericTypeEx())
                //        {
                //            if (baseType.GetGenericArgumentsEx()[0].IsInterfaceEx())
                //            {
                //                var genericTypeDefinition = baseType.GetGenericTypeDefinitionEx();

                //                var allPossibleMatchingTypes = (from type in serializerTypeInfo.SpecialGenericCollectionTypes
                //                                                where type.GetGenericTypeDefinitionEx() == genericTypeDefinition
                //                                                select type).ToList();

                //                if (allPossibleMatchingTypes.Count > 0)
                //                {
                //                    Log.Debug("Skipping type '{0}' because there already exists such a type which does the same", typeToAdd.GetSafeFullName());
                //                    return false;
                //                }
                //            }
                //        }

                //        baseType = baseType.GetBaseTypeEx();
                //    }
            }

            return(serializerTypeInfo.AddKnownType(typeToAdd));
        }
Ejemplo n.º 9
0
        protected virtual void GetKnownTypesForInstance(object obj, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (obj == null)
            {
                return;
            }

            var objectType = obj.GetType();

            if (ShouldTypeBeIgnored(objectType, serializerTypeInfo))
            {
                return;
            }

            GetKnownTypesForItemsInstance(obj, serializerTypeInfo);
            GetKnownTypes(objectType, serializerTypeInfo);
        }
        /// <summary>
        /// Gets the known types for a specific object instance.
        /// </summary>
        /// <param name="obj">The object to retrieve the known types for.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns>Array of <see cref="Type"/> that are found in the object instance.</returns>
        protected virtual void GetKnownTypesForInstance(object obj, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (obj == null)
            {
                return;
            }

            Type objectType = obj.GetType();

            if (ShouldTypeBeIgnored(objectType, serializerTypeInfo))
            {
                return;
            }

            GetKnownTypes(objectType, serializerTypeInfo);

            // Note: the code below is specific for instants of objects, cannot be moved to the GetKnownTypes

            if (objectType == typeof(List <KeyValuePair <string, object> >))
            {
                foreach (var keyValuePair in ((List <KeyValuePair <string, object> >)obj))
                {
                    GetKnownTypesForInstance(keyValuePair.Value, serializerTypeInfo);
                }
            }
            else if (objectType == typeof(List <PropertyValue>))
            {
                foreach (var propertyValue in ((List <PropertyValue>)obj))
                {
                    GetKnownTypesForInstance(propertyValue.Value, serializerTypeInfo);
                }
            }

            // Collections might contain interface types, so if this is an IEnumerable, we need to loop all the instances (performance warning!)
            else if ((obj is IEnumerable) && (!(obj is string)))
            {
                var objAsIEnumerable = (IEnumerable)obj;
                foreach (object item in objAsIEnumerable)
                {
                    if (item != null)
                    {
                        GetKnownTypesForInstance(item, serializerTypeInfo);
                    }
                }
            }
        }
Ejemplo n.º 11
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>
        /// Gets the Data Contract serializer for a specific type. This method caches serializers so the
        /// performance can be improved when a serializer is used more than once.
        /// </summary>
        /// <param name="serializingType">The type that is currently (de)serializing.</param>
        /// <param name="typeToSerialize">The type to (de)serialize.</param>
        /// <param name="xmlName">Name of the property as known in XML.</param>
        /// <param name="rootNamespace">The root namespace.</param>
        /// <param name="serializingObject">The object to create the serializer for. When the object is not <c>null</c>, the types that are
        /// a child object of this object are added to the known types of the serializer.</param>
        /// <param name="additionalKnownTypes">A list of additional types to add to the known types.</param>
        /// <returns><see cref="DataContractSerializer" /> for the given type.</returns>
        /// <exception cref="ArgumentNullException">The <paramref name="serializingType" /> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">The <paramref name="typeToSerialize" /> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">The <paramref name="xmlName" /> is <c>null</c> or whitespace.</exception>
        public virtual DataContractSerializer GetDataContractSerializer(Type serializingType, Type typeToSerialize, string xmlName, string rootNamespace = null, object serializingObject = null, List<Type> additionalKnownTypes = null)
        {
            Argument.IsNotNull("serializingType", serializingType);
            Argument.IsNotNull("typeToSerialize", typeToSerialize);
            Argument.IsNotNullOrWhitespace("xmlName", xmlName);

            string key = string.Format("{0}|{1}", typeToSerialize.GetSafeFullName(), xmlName);

            return _dataContractSerializersCache.GetFromCacheOrFetch(key, () =>
            {
                Log.Debug("Getting known types for xml serialization of '{0}'", typeToSerialize.GetSafeFullName());

                var serializerTypeInfo = new XmlSerializerTypeInfo(serializingType, typeToSerialize, additionalKnownTypes);

                if (serializingObject != null)
                {
                    GetKnownTypesForInstance(serializingObject, serializerTypeInfo);
                }
                else
                {
                    GetKnownTypes(typeToSerialize, serializerTypeInfo);
                }

                var knownTypesViaAttributes = GetKnownTypesViaAttributes(serializingType);
                foreach (var knownTypeViaAttribute in knownTypesViaAttributes)
                {
                    GetKnownTypes(knownTypeViaAttribute, serializerTypeInfo);
                }

                if (additionalKnownTypes != null)
                {
                    foreach (var additionalKnownType in additionalKnownTypes)
                    {
                        GetKnownTypes(additionalKnownType, serializerTypeInfo);
                    }
                }

                var xmlSerializer = new DataContractSerializer(typeToSerialize, xmlName, rootNamespace ?? string.Empty, serializerTypeInfo.KnownTypes);
                return xmlSerializer;
            });
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Determines whether the specified type is serializable.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type information.</param>
        /// <returns><c>true</c> if the specified type is serializable; otherwise, <c>false</c>.</returns>
        protected virtual bool IsTypeSerializable(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (type is null)
            {
                return(false);
            }

            // DataContract attribute
            if (type.IsDecoratedWithAttribute <DataContractAttribute>())
            {
                return(true);
            }

#if NET || NETCORE || NETSTANDARD
            // Implements ISerializable
            if (type.ImplementsInterfaceEx <ISerializable>())
            {
                return(true);
            }
#endif

            // Implements IXmlSerializer
            if (type.ImplementsInterfaceEx <System.Xml.Serialization.IXmlSerializable>())
            {
                return(true);
            }

            // Is ModelBase
            if (type.IsModelBase())
            {
                return(true);
            }

            // IsSerializable
            return(type.IsSerializableEx());
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Gets the known types for a specific type. This method caches the lists so the
        /// performance can be improved when a type is used more than once.
        /// </summary>
        /// <param name="serializingType">The type that is currently (de)serializing.</param>
        /// <param name="typeToSerialize">The type to (de)serialize.</param>
        /// <param name="additionalKnownTypes">A list of additional types to add to the known types.</param>
        /// <returns><see cref="DataContractSerializer" /> for the given type.</returns>
        /// <exception cref="ArgumentNullException">The <paramref name="serializingType" /> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">The <paramref name="typeToSerialize" /> is <c>null</c>.</exception>
        public virtual List <Type> GetKnownTypes(Type serializingType, Type typeToSerialize, List <Type> additionalKnownTypes = null)
        {
            Argument.IsNotNull("serializingType", serializingType);
            Argument.IsNotNull("typeToSerialize", typeToSerialize);

            var serializingTypeName = serializingType.GetSafeFullName(false);
            var typeToSerializeName = typeToSerialize.GetSafeFullName(false);
            var key = string.Format("{0}|{1}|{2}", serializingTypeName, typeToSerializeName, additionalKnownTypes?.Count ?? 0);

            return(_knownTypesCache.GetFromCacheOrFetch(key, () =>
            {
#if ENABLE_DETAILED_LOGGING
                Log.Debug("Getting known types for xml serialization of '{0}'", typeToSerializeName);
#endif

                var serializerTypeInfo = new XmlSerializerTypeInfo(serializingType, typeToSerialize, additionalKnownTypes);

                GetKnownTypes(typeToSerialize, serializerTypeInfo);

                var knownTypesViaAttributes = GetKnownTypesViaAttributes(serializingType);
                foreach (var knownTypeViaAttribute in knownTypesViaAttributes)
                {
                    GetKnownTypes(knownTypeViaAttribute, serializerTypeInfo);
                }

                if (additionalKnownTypes != null)
                {
                    foreach (var additionalKnownType in additionalKnownTypes)
                    {
                        GetKnownTypes(additionalKnownType, serializerTypeInfo);
                    }
                }

                return serializerTypeInfo.KnownTypes.ToList();
            }));
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Determines whether the specified type is serializable.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type information.</param>
        /// <returns><c>true</c> if the specified type is serializable; otherwise, <c>false</c>.</returns>
        protected virtual bool IsTypeSerializable(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (type == null)
            {
                return(false);
            }

            // DataContract attribute
            if (AttributeHelper.IsDecoratedWithAttribute <DataContractAttribute>(type))
            {
                return(true);
            }

#if NET
            // Implements ISerializable
            if (type.ImplementsInterfaceEx <ISerializable>())
            {
                return(true);
            }
#endif

            // Implements IXmlSerializer
            if (type.ImplementsInterfaceEx <System.Xml.Serialization.IXmlSerializable>())
            {
                return(true);
            }

            // Is ModelBase
            if (typeof(ModelBase).IsAssignableFromEx(type))
            {
                return(true);
            }

            // IsSerializable
            return(type.IsSerializableEx());
        }
        private void GetKnownTypesForItemsInstance(object obj, XmlSerializerTypeInfo serializerTypeInfo)
        {
            var ienumerable = obj as IEnumerable;

            if (ienumerable != null)
            {
                foreach (var item in ienumerable)
                {
                    GetKnownTypesForInstance(item, serializerTypeInfo);
                }
            }
        }
 /// <summary>
 /// Gets the known types of IEnumerable 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>
 private void GetKnownTypesForItems(Type type, XmlSerializerTypeInfo serializerTypeInfo)
 {
     if (type.ImplementsInterfaceEx<IEnumerable>())
     {
         foreach (var argument in type.GetGenericArgumentsEx())
         {
             GetKnownTypes(argument, 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);
                    }
                }
            }
        }
        protected virtual void GetKnownTypesForInstance(object obj, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (obj == null)
            {
                return;
            }

            var objectType = obj.GetType();

            if (ShouldTypeBeIgnored(objectType, serializerTypeInfo))
            {
                return;
            }

            GetKnownTypesForItemsInstance(obj, serializerTypeInfo);
            GetKnownTypes(objectType, serializerTypeInfo);
        }
        /// <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 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 for a specific object instance.
        /// </summary>
        /// <param name="obj">The object to retrieve the known types for.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns>Array of <see cref="Type"/> that are found in the object instance.</returns>
        protected virtual void GetKnownTypesForInstance(object obj, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (obj == null)
            {
                return;
            }

            Type objectType = obj.GetType();

            if (ShouldTypeBeIgnored(objectType, serializerTypeInfo))
            {
                return;
            }

            GetKnownTypes(objectType, serializerTypeInfo);

            // Note: the code below is specific for instants of objects, cannot be moved to the GetKnownTypes

            if (objectType == typeof(List<KeyValuePair<string, object>>))
            {
                foreach (var keyValuePair in ((List<KeyValuePair<string, object>>)obj))
                {
                    GetKnownTypesForInstance(keyValuePair.Value, serializerTypeInfo);
                }
            }
            else if (objectType == typeof(List<PropertyValue>))
            {
                foreach (var propertyValue in ((List<PropertyValue>)obj))
                {
                    GetKnownTypesForInstance(propertyValue.Value, serializerTypeInfo);
                }
            }

            // Collections might contain interface types, so if this is an IEnumerable, we need to loop all the instances (performance warning!)
            else if ((obj is IEnumerable) && (!(obj is string)))
            {
                var objAsIEnumerable = (IEnumerable)obj;
                foreach (object item in objAsIEnumerable)
                {
                    if (item != null)
                    {
                        GetKnownTypesForInstance(item, serializerTypeInfo);
                    }
                }
            }
        }
        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>
        /// 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);
        }
        /// <summary>
        /// Determines whether the specified type is serializable.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="serializerTypeInfo">The serializer type information.</param>
        /// <returns><c>true</c> if the specified type is serializable; otherwise, <c>false</c>.</returns>
        protected virtual bool IsTypeSerializable(Type type, XmlSerializerTypeInfo serializerTypeInfo)
        {
            if (type == null)
            {
                return false;
            }

            // DataContract attribute
            if (AttributeHelper.IsDecoratedWithAttribute<DataContractAttribute>(type))
            {
                return true;
            }

#if NET
            // Implements ISerializable
            if (type.ImplementsInterfaceEx<ISerializable>())
            {
                return true;
            }
#endif

            // Implements IXmlSerializer
            if (type.ImplementsInterfaceEx<System.Xml.Serialization.IXmlSerializable>())
            {
                return true;
            }

            // Is ModelBase
            if (type.IsModelBase())
            {
                return true;
            }

            // IsSerializable
            return type.IsSerializableEx();
        }
        /// <summary>
        /// Adds the type to the known types if the type is serializable.
        /// </summary>
        /// <param name="typeToAdd">The type to add.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns><c>true</c> if the type is serializable; otherwise <c>false</c>.</returns>
        protected virtual bool AddTypeToKnownTypesIfSerializable(Type typeToAdd, XmlSerializerTypeInfo serializerTypeInfo)
        {
            // Collection first, this collection of types is smaller so if we have a hit, we exit sooner
            if (serializerTypeInfo.IsCollectionAlreadyHandled(typeToAdd))
            {
                return true;
            }

            if (serializerTypeInfo.ContainsKnownType(typeToAdd))
            {
                return true;
            }

            serializerTypeInfo.AddCollectionAsHandled(typeToAdd);

            // If this is a special collection type (generic), then we need to make sure that if the inner type is
            // an interface, we do not add it again if already added.
            // See this issue http://catel.codeplex.com/workitem/7167
            if (serializerTypeInfo.IsSpecialCollectionType(typeToAdd))
            {
                // Always ignore as a test
                return false;

                // TODO: Also check interfaces
                //    // It might be a base type, loop all
                //    var baseType = typeToAdd;
                //    while (baseType != null)
                //    {
                //        if (baseType.IsGenericTypeEx())
                //        {
                //            if (baseType.GetGenericArgumentsEx()[0].IsInterfaceEx())
                //            {
                //                var genericTypeDefinition = baseType.GetGenericTypeDefinitionEx();

                //                var allPossibleMatchingTypes = (from type in serializerTypeInfo.SpecialGenericCollectionTypes
                //                                                where type.GetGenericTypeDefinitionEx() == genericTypeDefinition
                //                                                select type).ToList();

                //                if (allPossibleMatchingTypes.Count > 0)
                //                {
                //                    Log.Debug("Skipping type '{0}' because there already exists such a type which does the same", typeToAdd.GetSafeFullName());
                //                    return false;
                //                }
                //            }
                //        }

                //        baseType = baseType.GetBaseTypeEx();
                //    }
            }

            return serializerTypeInfo.AddKnownType(typeToAdd);
        }
        /// <summary>
        /// Adds the type to the known types if the type is serializable.
        /// </summary>
        /// <param name="typeToAdd">The type to add.</param>
        /// <param name="serializerTypeInfo">The serializer type info.</param>
        /// <returns><c>true</c> if the type is serializable; otherwise <c>false</c>.</returns>
        protected virtual bool AddTypeToKnownTypesIfSerializable(Type typeToAdd, XmlSerializerTypeInfo serializerTypeInfo)
        {
            // Collection first, this collection of types is smaller so if we have a hit, we exit sooner
            if (serializerTypeInfo.IsCollectionAlreadyHandled(typeToAdd))
            {
                return true;
            }

            if (serializerTypeInfo.ContainsKnownType(typeToAdd))
            {
                return true;
            }

            serializerTypeInfo.AddCollectionAsHandled(typeToAdd);

            // If this is a special collection type (generic), then we need to make sure that if the inner type is
            // an interface, we do not add it again if already added.
            // See this issue http://catel.codeplex.com/workitem/7167
            if (serializerTypeInfo.IsSpecialCollectionType(typeToAdd))
            {
                // Always ignore
                return false;
            }

            return serializerTypeInfo.AddKnownType(typeToAdd);
        }
Ejemplo n.º 29
0
        /// <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);
                    }
                }
            }
        }