// Reduce IL2CPP code generate size(don't write long code in <T>) internal static object GetFormatter(Type t) { if (t.IsArray) { var rank = t.GetArrayRank(); if (rank == 1) { if (t.GetElementType() == typeof(byte)) // byte[] is also supported in builtin formatter. { return(ByteArrayFormatter.Default); } return(Activator.CreateInstance(typeof(ArrayFormatter <>).MakeGenericType(t.GetElementType()))); } if (rank == 2) { return(Activator.CreateInstance(typeof(TwoDimensionalArrayFormatter <>).MakeGenericType(t.GetElementType()))); } if (rank == 3) { return(Activator.CreateInstance(typeof(ThreeDimensionalArrayFormatter <>).MakeGenericType(t.GetElementType()))); } if (rank == 4) { return(Activator.CreateInstance(typeof(FourDimensionalArrayFormatter <>).MakeGenericType(t.GetElementType()))); } return(null); // not supported built-in } if (t.IsGenericType) { var genericType = t.GetGenericTypeDefinition(); var isNullable = ReflectionExtensions.IsNullable(genericType); var nullableElementType = isNullable ? t.GenericTypeArguments[0] : null; if (genericType == typeof(KeyValuePair <,>)) { return(CreateInstance(typeof(KeyValuePairFormatter <,>), t.GenericTypeArguments)); } if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>)) { return(CreateInstance(typeof(NullableFormatter <>), new[] { nullableElementType })); } #if NETSTANDARD2_1 // ValueTask if (genericType == typeof(ValueTask <>)) { return(CreateInstance(typeof(ValueTaskFormatter <>), t.GenericTypeArguments)); } if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.GetGenericTypeDefinition() == typeof(ValueTask <>)) { return(CreateInstance(typeof(NullableFormatter <>), new[] { nullableElementType })); } #endif // Tuple if (t.FullName.StartsWith("System.Tuple")) { Type tupleFormatterType = null; switch (t.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, t.GenericTypeArguments)); } #if NETSTANDARD // ValueTuple if (t.FullName.StartsWith("System.ValueTuple")) { Type tupleFormatterType = null; switch (t.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, t.GenericTypeArguments)); } // Nullable ValueTuple if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.FullName.StartsWith("System.ValueTuple")) { Type tupleFormatterType = null; switch (nullableElementType.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; } var tupleFormatter = CreateInstance(tupleFormatterType, nullableElementType.GenericTypeArguments); return(CreateInstance(typeof(StaticNullableFormatter <>), new[] { nullableElementType }, tupleFormatter)); } #endif // ArraySegment if (genericType == typeof(ArraySegment <>)) { if (t.GenericTypeArguments[0] == typeof(byte)) { return(ByteArraySegmentFormatter.Default); } return(CreateInstance(typeof(ArraySegmentFormatter <>), t.GenericTypeArguments)); } if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.GetGenericTypeDefinition() == typeof(ArraySegment <>)) { if (nullableElementType == typeof(ArraySegment <byte>)) { return(new StaticNullableFormatter <ArraySegment <byte> >(ByteArraySegmentFormatter.Default)); } return(CreateInstance(typeof(NullableFormatter <>), new[] { nullableElementType })); } // Mapped formatter if (FormatterMap.TryGetValue(genericType, out var formatterType)) { return(CreateInstance(formatterType, t.GenericTypeArguments)); } // generic collection if (t.GenericTypeArguments.Length == 1 && t.GetInterfaces().Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(ICollection <>)) && t.GetDeclaredConstructors().Any(x => x.GetParameters().Length == 0)) { var elemType = t.GenericTypeArguments[0]; return(CreateInstance(typeof(GenericCollectionFormatter <,>), new[] { elemType, t })); } // generic dictionary if (t.GenericTypeArguments.Length == 2 && t.GetInterfaces().Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary <,>)) && t.GetDeclaredConstructors().Any(x => x.GetParameters().Length == 0)) { var keyType = t.GenericTypeArguments[0]; var valueType = t.GenericTypeArguments[1]; return(CreateInstance(typeof(GenericDictionaryFormatter <, ,>), new[] { keyType, valueType, t })); } } else { // NonGeneric Collection if (t == typeof(IEnumerable)) { return(NonGenericInterfaceEnumerableFormatter.Default); } if (t == typeof(ICollection)) { return(NonGenericInterfaceCollectionFormatter.Default); } if (t == typeof(IList)) { return(NonGenericInterfaceListFormatter.Default); } if (t == typeof(IDictionary)) { return(NonGenericInterfaceDictionaryFormatter.Default); } if (typeof(IList).IsAssignableFrom(t) && t.GetDeclaredConstructors().Any(x => x.GetParameters().Length == 0)) { return(Activator.CreateInstance(typeof(NonGenericListFormatter <>).MakeGenericType(t))); } if (typeof(IDictionary).IsAssignableFrom(t) && t.GetDeclaredConstructors().Any(x => x.GetParameters().Length == 0)) { return(Activator.CreateInstance(typeof(NonGenericDictionaryFormatter <>).MakeGenericType(t))); } } return(null); }