#if !UNITY_WSA using MessagePack.Formatters; using System.Linq; using MessagePack.Internal; using System; using System.Collections.Generic; using System.Reflection; using System.Collections.ObjectModel; using System.Collections; #if NETSTANDARD using System.Threading.Tasks; #endif namespace MessagePack.Resolvers { public sealed class DynamicGenericResolver : IFormatterResolver { public static readonly IFormatterResolver Instance = new DynamicGenericResolver(); DynamicGenericResolver() { } public IMessagePackFormatter GetFormatter() { return FormatterCache.formatter; } static class FormatterCache { public static readonly IMessagePackFormatter formatter; static FormatterCache() { formatter = (IMessagePackFormatter)DynamicGenericResolverGetFormatterHelper.GetFormatter(typeof(T)); } } } } namespace MessagePack.Internal { internal static class DynamicGenericResolverGetFormatterHelper { static readonly Dictionary formatterMap = new Dictionary() { {typeof(List<>), typeof(ListFormatter<>)}, {typeof(LinkedList<>), typeof(LinkedListFormatter<>)}, {typeof(Queue<>), typeof(QeueueFormatter<>)}, {typeof(Stack<>), typeof(StackFormatter<>)}, {typeof(HashSet<>), typeof(HashSetFormatter<>)}, {typeof(ReadOnlyCollection<>), typeof(ReadOnlyCollectionFormatter<>)}, {typeof(IList<>), typeof(InterfaceListFormatter<>)}, {typeof(ICollection<>), typeof(InterfaceCollectionFormatter<>)}, {typeof(IEnumerable<>), typeof(InterfaceEnumerableFormatter<>)}, {typeof(Dictionary<,>), typeof(DictionaryFormatter<,>)}, {typeof(IDictionary<,>), typeof(InterfaceDictionaryFormatter<,>)}, {typeof(SortedDictionary<,>), typeof(SortedDictionaryFormatter<,>)}, {typeof(SortedList<,>), typeof(SortedListFormatter<,>)}, {typeof(ILookup<,>), typeof(InterfaceLookupFormatter<,>)}, {typeof(IGrouping<,>), typeof(InterfaceGroupingFormatter<,>)}, #if NETSTANDARD {typeof(ObservableCollection<>), typeof(ObservableCollectionFormatter<>)}, {typeof(ReadOnlyObservableCollection<>),(typeof(ReadOnlyObservableCollectionFormatter<>))}, {typeof(IReadOnlyList<>), typeof(InterfaceReadOnlyListFormatter<>)}, {typeof(IReadOnlyCollection<>), typeof(InterfaceReadOnlyCollectionFormatter<>)}, {typeof(ISet<>), typeof(InterfaceSetFormatter<>)}, {typeof(System.Collections.Concurrent.ConcurrentBag<>), typeof(ConcurrentBagFormatter<>)}, {typeof(System.Collections.Concurrent.ConcurrentQueue<>), typeof(ConcurrentQueueFormatter<>)}, {typeof(System.Collections.Concurrent.ConcurrentStack<>), typeof(ConcurrentStackFormatter<>)}, {typeof(ReadOnlyDictionary<,>), typeof(ReadOnlyDictionaryFormatter<,>)}, {typeof(IReadOnlyDictionary<,>), typeof(InterfaceReadOnlyDictionaryFormatter<,>)}, {typeof(System.Collections.Concurrent.ConcurrentDictionary<,>), typeof(ConcurrentDictionaryFormatter<,>)}, {typeof(Lazy<>), typeof(LazyFormatter<>)}, {typeof(Task<>), typeof(TaskValueFormatter<>)}, #endif }; // Reduce IL2CPP code generate size(don't write long code in ) internal static object GetFormatter(Type t) { var ti = t.GetTypeInfo(); if (t.IsArray) { var rank = t.GetArrayRank(); if (rank == 1) { if (t.GetElementType() == typeof(byte)) // byte[] is also supported in builtin formatter. { return ByteArrayFormatter.Instance; } return Activator.CreateInstance(typeof(ArrayFormatter<>).MakeGenericType(t.GetElementType())); } else if (rank == 2) { return Activator.CreateInstance(typeof(TwoDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType())); } else if (rank == 3) { return Activator.CreateInstance(typeof(ThreeDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType())); } else if (rank == 4) { return Activator.CreateInstance(typeof(FourDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType())); } else { return null; // not supported built-in } } else if (ti.IsGenericType) { var genericType = ti.GetGenericTypeDefinition(); var genericTypeInfo = genericType.GetTypeInfo(); var isNullable = genericTypeInfo.IsNullable(); var nullableElementType = isNullable ? ti.GenericTypeArguments[0] : null; if (genericType == typeof(KeyValuePair<,>)) { return CreateInstance(typeof(KeyValuePairFormatter<,>), ti.GenericTypeArguments); } else if (isNullable && nullableElementType.GetTypeInfo().IsConstructedGenericType() && nullableElementType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) { return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType }); } #if NETSTANDARD // ValueTask else if (genericType == typeof(ValueTask<>)) { return CreateInstance(typeof(ValueTaskFormatter<>), ti.GenericTypeArguments); } else if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.GetGenericTypeDefinition() == typeof(ValueTask<>)) { return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType }); } // Tuple else if (ti.FullName.StartsWith("System.Tuple")) { Type tupleFormatterType = null; switch (ti.GenericTypeArguments.Length) { case 1: tupleFormatterType = typeof(TupleFormatter<>); break; case 2: tupleFormatterType = typeof(TupleFormatter<,>); break; case 3: tupleFormatterType = typeof(TupleFormatter<,,>); break; case 4: tupleFormatterType = typeof(TupleFormatter<,,,>); break; case 5: tupleFormatterType = typeof(TupleFormatter<,,,,>); break; case 6: tupleFormatterType = typeof(TupleFormatter<,,,,,>); break; case 7: tupleFormatterType = typeof(TupleFormatter<,,,,,,>); break; case 8: tupleFormatterType = typeof(TupleFormatter<,,,,,,,>); break; default: break; } return CreateInstance(tupleFormatterType, ti.GenericTypeArguments); } // ValueTuple else if (ti.FullName.StartsWith("System.ValueTuple")) { Type tupleFormatterType = null; switch (ti.GenericTypeArguments.Length) { case 1: tupleFormatterType = typeof(ValueTupleFormatter<>); break; case 2: tupleFormatterType = typeof(ValueTupleFormatter<,>); break; case 3: tupleFormatterType = typeof(ValueTupleFormatter<,,>); break; case 4: tupleFormatterType = typeof(ValueTupleFormatter<,,,>); break; case 5: tupleFormatterType = typeof(ValueTupleFormatter<,,,,>); break; case 6: tupleFormatterType = typeof(ValueTupleFormatter<,,,,,>); break; case 7: tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,>); break; case 8: tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,,>); break; default: break; } return CreateInstance(tupleFormatterType, ti.GenericTypeArguments); } #endif // ArraySegement else if (genericType == typeof(ArraySegment<>)) { if (ti.GenericTypeArguments[0] == typeof(byte)) { return ByteArraySegmentFormatter.Instance; } else { return CreateInstance(typeof(ArraySegmentFormatter<>), ti.GenericTypeArguments); } } else if (isNullable && nullableElementType.GetTypeInfo().IsConstructedGenericType() && nullableElementType.GetGenericTypeDefinition() == typeof(ArraySegment<>)) { if (nullableElementType == typeof(ArraySegment)) { return new StaticNullableFormatter>(ByteArraySegmentFormatter.Instance); } else { return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType }); } } // Mapped formatter else { Type formatterType; if (formatterMap.TryGetValue(genericType, out formatterType)) { return CreateInstance(formatterType, ti.GenericTypeArguments); } // generic collection else if (ti.GenericTypeArguments.Length == 1 && ti.ImplementedInterfaces.Any(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(ICollection<>)) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) { var elemType = ti.GenericTypeArguments[0]; return CreateInstance(typeof(GenericCollectionFormatter<,>), new[] { elemType, t }); } // generic dictionary else if (ti.GenericTypeArguments.Length == 2 && ti.ImplementedInterfaces.Any(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) { var keyType = ti.GenericTypeArguments[0]; var valueType = ti.GenericTypeArguments[1]; return CreateInstance(typeof(GenericDictionaryFormatter<,,>), new[] { keyType, valueType, t }); } } } else { // NonGeneric Collection if (t == typeof(IList)) { return NonGenericInterfaceListFormatter.Instance; } else if (t == typeof(IDictionary)) { return NonGenericInterfaceDictionaryFormatter.Instance; } if (typeof(IList).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) { return Activator.CreateInstance(typeof(NonGenericListFormatter<>).MakeGenericType(t)); } else if (typeof(IDictionary).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) { return Activator.CreateInstance(typeof(NonGenericDictionaryFormatter<>).MakeGenericType(t)); } } return null; } static object CreateInstance(Type genericType, Type[] genericTypeArguments, params object[] arguments) { return Activator.CreateInstance(genericType.MakeGenericType(genericTypeArguments), arguments); } } } #endif