static KeyframeFormatter()
        {
            Is_In_2018_1_Or_Above = typeof(Keyframe).GetProperty("weightedMode") != null;

            if (Is_In_2018_1_Or_Above)
            {
                if (EmitUtilities.CanEmit)
                {
                    Formatter = (IFormatter <Keyframe>)FormatterEmitter.GetEmittedFormatter(typeof(Keyframe), SerializationPolicies.Everything);
                }
                else
                {
                    Formatter = new ReflectionFormatter <Keyframe>(SerializationPolicies.Everything);
                }
            }
        }
        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);
            }

            // First call formatter locators before checking for registered formatters
            for (int i = 0; i < FormatterLocators.Count; i++)
            {
                try
                {
                    IFormatter result;
                    if (FormatterLocators[i].LocatorInstance.TryGetFormatter(type, FormatterLocationStep.BeforeRegisteredFormatters, policy, out result))
                    {
                        return(result);
                    }
                }
                catch (TargetInvocationException ex)
                {
                    throw ex;
                }
                catch (TypeInitializationException ex)
                {
                    throw ex;
                }
#pragma warning disable CS0618 // Type or member is obsolete
                catch (ExecutionEngineException ex)
#pragma warning restore CS0618 // Type or member is obsolete
                {
                    throw ex;
                }
                catch (Exception ex)
                {
                    Debug.LogException(new Exception("Exception was thrown while calling FormatterLocator " + FormatterLocators[i].GetType().FullName + ".", ex));
                }
            }

            // Then check for valid registered formatters
            for (int i = 0; i < FormatterInfos.Count; i++)
            {
                var info = FormatterInfos[i];

                Type formatterType = null;

                if (type == info.TargetType)
                {
                    formatterType = info.FormatterType;
                }
                else if (info.FormatterType.IsGenericType && info.TargetType.IsGenericParameter)
                {
                    Type[] inferredArgs;

                    if (info.FormatterType.TryInferGenericParameters(out inferredArgs, type))
                    {
                        formatterType = info.FormatterType.GetGenericTypeDefinition().MakeGenericType(inferredArgs);
                    }
                }
                else if (type.IsGenericType && info.FormatterType.IsGenericType && info.TargetType.IsGenericType && type.GetGenericTypeDefinition() == info.TargetType.GetGenericTypeDefinition())
                {
                    Type[] args = type.GetGenericArguments();

                    if (info.FormatterType.AreGenericConstraintsSatisfiedBy(args))
                    {
                        formatterType = info.FormatterType.GetGenericTypeDefinition().MakeGenericType(args);
                    }
                }

                if (formatterType != null)
                {
                    var instance = GetFormatterInstance(formatterType);

                    if (instance == null)
                    {
                        continue;
                    }

                    if (info.AskIfCanFormatTypes && !((IAskIfCanFormatTypes)instance).CanFormatType(type))
                    {
                        continue;
                    }

                    return(instance);
                }
            }

            // Then call formatter locators after checking for registered formatters
            for (int i = 0; i < FormatterLocators.Count; i++)
            {
                try
                {
                    IFormatter result;
                    if (FormatterLocators[i].LocatorInstance.TryGetFormatter(type, FormatterLocationStep.AfterRegisteredFormatters, policy, out result))
                    {
                        return(result);
                    }
                }
                catch (TargetInvocationException ex)
                {
                    throw ex;
                }
                catch (TypeInitializationException ex)
                {
                    throw ex;
                }
#pragma warning disable CS0618 // Type or member is obsolete
                catch (ExecutionEngineException ex)
#pragma warning restore CS0618 // Type or member is obsolete
                {
                    throw ex;
                }
                catch (Exception ex)
                {
                    Debug.LogException(new Exception("Exception was thrown while calling FormatterLocator " + FormatterLocators[i].GetType().FullName + ".", ex));
                }
            }

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

            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)));
        }
        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)));
        }