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