Example #1
0
        public bool TryGetFormatter(Type type, FormatterLocationStep step, ISerializationPolicy policy, out IFormatter formatter)
        {
            Type elementType;

            if (step != FormatterLocationStep.AfterRegisteredFormatters || !GenericCollectionFormatter.CanFormat(type, out elementType))
            {
                formatter = null;
                return(false);
            }

            formatter = (IFormatter)Activator.CreateInstance(typeof(GenericCollectionFormatter <,>).MakeGenericType(type, elementType));
            return(true);
        }
        private static IFormatter CreateFormatter(Type type, ISerializationPolicy policy)
        {
            if (FormatterUtilities.IsPrimitiveType(type))
            {
                throw new ArgumentException("Cannot create formatters for a primitive type like " + type.Name);
            }

            bool canSelfFormat = type.ImplementsOrInherits(typeof(ISelfFormatter));

            // If the type should always self format, there is no need to explore further.
            // Otherwise, we go through the below checks first to see whether a custom
            // formatter is defined.
            if (canSelfFormat && type.IsDefined <AlwaysFormatsSelfAttribute>())
            {
                return((IFormatter)Activator.CreateInstance(typeof(SelfFormatterFormatter <>).MakeGenericType(type)));
            }

            // First, allow the FormatterResolve event to resolve the formatter if possible
            // We always hold the lock in the CreateFormatter method, so we can safely
            //  invoke the event without worrying about other threads changing it.
            if (FormatterResolvePrivate != null)
            {
                Type genericInterface = typeof(IFormatter <>).MakeGenericType(type);

                foreach (var del in FormatterResolvePrivate.GetInvocationList())
                {
                    IFormatter result = del.Method.Invoke(del.Target, new object[] { type }) as IFormatter;

                    if (result != null && result.GetType().ImplementsOrInherits(genericInterface))
                    {
                        return(result);
                    }
                }
            }

            // Then try to find a custom formatter
            {
                Type formatterType;

                if (CustomFormatterTypes.TryGetValue(type, out formatterType))
                {
                    return((IFormatter)Activator.CreateInstance(formatterType));
                }
            }

            if (type.IsGenericType)
            {
                // Then try to find a custom generic formatter.
                // IE, if we're trying to serialize Dictionary<string, int>, we might have a formatter that declares it can handle
                // Dictionary<TKey, TValue>. If so, we can use that.
                Type genericTypeDefinition = type.GetGenericTypeDefinition();
                Type formatterGenericTypeDefinition;

                if (CustomGenericFormatterTypes.TryGetValue(genericTypeDefinition, out formatterGenericTypeDefinition))
                {
                    var formatterType = formatterGenericTypeDefinition.MakeGenericType(type.GetGenericArguments());
                    return((IFormatter)Activator.CreateInstance(formatterType));
                }
            }

            // Quick hack to support types derived from dictionary
            if (type.ImplementsOpenGenericClass(typeof(Dictionary <,>)) && type.GetConstructor(Type.EmptyTypes) != null)
            {
                var dictArgs      = type.GetArgumentsOfInheritedOpenGenericClass(typeof(Dictionary <,>));
                var formatterType = typeof(DerivedDictionaryFormatter <, ,>).MakeGenericType(type, dictArgs[0], dictArgs[1]);
                return((IFormatter)Activator.CreateInstance(formatterType));
            }

            // If there were no custom formatters found, the type can format itself
            if (canSelfFormat)
            {
                return((IFormatter)Activator.CreateInstance(typeof(SelfFormatterFormatter <>).MakeGenericType(type)));
            }

            // Delegates get special behaviour, as they're weird
            if (typeof(Delegate).IsAssignableFrom(type))
            {
                return((IFormatter)Activator.CreateInstance(typeof(DelegateFormatter <>).MakeGenericType(type)));
            }

            // Types get special behaviour, as they are often instances of special runtime types like System.MonoType which cannot be addressed at compile time.
            if (typeof(Type).IsAssignableFrom(type))
            {
                return(new TypeFormatter());
            }

            if (type.IsArray)
            {
                // Custom behaviour for all arrays that don't have specific custom formatters
                if (type.GetArrayRank() == 1)
                {
                    if (FormatterUtilities.IsPrimitiveArrayType(type.GetElementType()))
                    {
                        return((IFormatter)Activator.CreateInstance(typeof(PrimitiveArrayFormatter <>).MakeGenericType(type.GetElementType())));
                    }
                    else
                    {
                        return((IFormatter)Activator.CreateInstance(typeof(ArrayFormatter <>).MakeGenericType(type.GetElementType())));
                    }
                }
                else
                {
                    return((IFormatter)Activator.CreateInstance(typeof(MultiDimensionalArrayFormatter <,>).MakeGenericType(type, type.GetElementType())));
                }
            }

            // If the type implements ISerializable, use the SerializableFormatter
            if (type.ImplementsOrInherits(typeof(ISerializable)))
            {
                return((IFormatter)Activator.CreateInstance(typeof(SerializableFormatter <>).MakeGenericType(type)));
            }

            // If the type can be treated as a generic collection, do that
            {
                Type elementType;

                if (GenericCollectionFormatter.CanFormat(type, out elementType))
                {
                    return((IFormatter)Activator.CreateInstance(typeof(GenericCollectionFormatter <,>).MakeGenericType(type, elementType)));
                }
            }

            // If we can, emit a formatter to handle serialization of this object
            {
                if (EmitUtilities.CanEmit)
                {
                    return(FormatterEmitter.GetEmittedFormatter(type, policy));
                }
            }

            if (EmitUtilities.CanEmit)
            {
                Debug.LogWarning("Fallback to reflection for type " + type.Name + " when emit is possible on this platform.");
            }

            // Finally, we fall back to a reflection-based formatter if nothing else has been found
            return((IFormatter)Activator.CreateInstance(typeof(ReflectionFormatter <>).MakeGenericType(type)));
        }