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(false));
#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(false).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(false), type.GetSafeFullName(false));
#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(false));
#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(false));
#endif
foreach (var knownTypeByAttribute in knowTypesByAttributes)
{
var attributeType = knownTypeByAttribute;
var attributeTypeFullName = attributeType.GetSafeFullName(false);
if (attributeTypeFullName != null)
{
GetKnownTypes(knownTypeByAttribute, serializerTypeInfo);
}
else
{
serializerTypeInfo.AddTypeAsHandled(attributeType);
}
}
}
}