using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace CPF.Windows.Json.Serializer { internal class FormatterFind { internal static Action Find() { Type t = typeof(T); return FindTypeIsDefaultImplemented(t) ?? FindTypeIsMeetDefaultCondition(t) ?? FindTypeIsDefaultImplementedBaseType(t) ?? FindTypeIsDefaultImplementedInterface(t) ?? DefaultResolve(t); } private static Action FindTypeIsDefaultImplemented(Type t) { if (SerializerBootTable.Table.DefaultSameTypes.TryGetValue(t, out MethodInfo value)) return GenerateLambdaCall(value); return null; } private static Action FindTypeIsMeetDefaultCondition(Type t) { return IsLoadDynamic(t) ?? IsArray(t) ?? IsEnum(t); } private static Action FindTypeIsDefaultImplementedBaseType(Type t) { var baseTypes = t.GetTypeAndBaseTypes(); //Avoid if (SerializerBootTable.Table.DefaultAvoidTypes.Intersect(baseTypes).Any()) return (a, b) => SpecialConditions.AvoidTypes(a, b); //Default foreach (var implementedType in SerializerBootTable.Table.DefaultImplementedBaseType) { foreach (var baseType in baseTypes) { if (baseType == implementedType.Key) { return GenerateLambdaCall(implementedType.Value.MethodInfo); } } } return null; } private static Action FindTypeIsDefaultImplementedInterface(Type t) { var intserfaces = t.GetInterfaces().ToList(); if (t.IsInterface) intserfaces.Add(t); foreach (var item in SerializerBootTable.Table.DefaultImplementedInterfaces) { foreach (var objInterface in intserfaces) { if (objInterface == item.Key) { return GenerateLambdaCall(item.Value.MethodInfo); } } } return null; } private static Action DefaultResolve(Type t) { Func> func = TypeIsDictionary(t) ?? TypeIsCollection(t) ?? TypeIsSpecial(t); if (func != null) return func(); return BuildFactory.Create(SerializerBuildTypeEnum.KeyValueObject); } private static Func> TypeIsDictionary(Type t) { return TypeIsDictionaryInterface(t) ?? TypeIsDictionaryType(t); } private static Func> TypeIsDictionaryInterface(Type t) { if (t == typeof(IDictionary)) return () => (obj, handler) => SpecialConditions.WriteDictionary((IDictionary)obj, handler); if (t.IsGenericType) { Type[] args = t.GetGenericArguments(); if (args.Length != 2) return null; var genericTypeDefinition = t.GetGenericTypeDefinition(); var keyType = args[0]; var valueType = args[1]; if (genericTypeDefinition == typeof(IDictionary<,>) #if !Net4 || genericTypeDefinition == typeof(IReadOnlyDictionary<,>) #endif ) return () => IsWrongKeyType(keyType) ?? BuildFactory.Create(SerializerBuildTypeEnum.IDictionaryGeneric); } return null; } private static Func> TypeIsDictionaryType(Type t) { if (t.IsInterface) return null; var intserfaces = t.GetInterfaces(); bool hasIDictionaryGeneric = false; bool hasIDictionary = false; Type iDictionaryGenericType = null; Type keyType = null; Type valueType = null; foreach (var item in intserfaces) { if (item.IsGenericType) { var genericTypeDefinition = item.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(IDictionary<,>)) { iDictionaryGenericType = item; hasIDictionaryGeneric = true; keyType = item.GetGenericArguments()[0]; valueType = item.GetGenericArguments()[1]; } } if (item == typeof(IDictionary)) hasIDictionary = true; } if (hasIDictionaryGeneric) { var ctor = t.GetDefaultNoArgCtorOrAppointTypeCtor(iDictionaryGenericType); if (ctor == null) { foreach (var item in t.GetConstructors()) { if (item.GetParameters().Length == 1) { var firstCtor = item.GetParameters()[0]; if (TypeIsDictionary(firstCtor.ParameterType) != null) { return () => IsWrongKeyType(keyType) ?? BuildFactory.Create(SerializerBuildTypeEnum.IDictionaryGeneric); } } } } else if (ctor.GetParameters().Length == 0) { return () => IsWrongKeyType(keyType) ?? BuildFactory.Create(SerializerBuildTypeEnum.IDictionaryGeneric); } else return () => IsWrongKeyType(keyType) ?? BuildFactory.Create(SerializerBuildTypeEnum.IDictionaryGeneric); } if (hasIDictionary) { var ctor = t.GetDefaultNoArgCtorOrAppointTypeCtor(typeof(IDictionary)); if (ctor == null) { foreach (var item in t.GetConstructors()) { if (item.GetParameters().Length == 1) { var firstCtor = item.GetParameters()[0]; if (TypeIsDictionary(firstCtor.ParameterType) != null) { return () => (obj, handler) => SpecialConditions.WriteDictionary((IDictionary)obj, handler); } } } } else if (ctor.GetParameters().Length == 0) { return () => (obj, handler) => SpecialConditions.WriteDictionary((IDictionary)obj, handler); } else return () => (obj, handler) => SpecialConditions.WriteDictionary((IDictionary)obj, handler); } return null; } private static Func> TypeIsCollection(Type t) { return TypeIsCollectionInterface(t) ?? TypeIsCollectionType(t); } private static Func> TypeIsCollectionInterface(Type t) { if (t == typeof(IEnumerable) || t == typeof(ICollection) || t == typeof(IList)) return () => (obj, handler) => SpecialConditions.WriteCollection((IEnumerable)obj, handler); if (t.IsGenericType) { var genericTypeDefinition = t.GetGenericTypeDefinition(); var arrayItemType = t.GetGenericArguments()[0]; if (genericTypeDefinition == typeof(IEnumerable<>) || genericTypeDefinition == typeof(IList<>) || genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(ISet<>) #if !Net4 || genericTypeDefinition == typeof(IReadOnlyList<>) || genericTypeDefinition == typeof(IReadOnlyCollection<>) #endif ) { return () => BuildFactory.Create(SerializerBuildTypeEnum.IEnumerableGeneric); } } return null; } private static Func> TypeIsCollectionType(Type t) { if (t.IsInterface) return null; var intserfaces = t.GetInterfaces(); bool hasIEnumerableGeneric = false; bool hasICollectionGeneric = false; bool hasIListGeneric = false; bool hasICollection = false; bool hasIList = false; Type arrayItemType = null; Type iCollectionGenericType = null; Type iEnumerableGenericType = null; Type iListGenericType = null; foreach (var item in intserfaces) { if (item.IsGenericType) { var genericTypeDefinition = item.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(IEnumerable<>)) { hasIEnumerableGeneric = true; arrayItemType = item.GetGenericArguments()[0]; iEnumerableGenericType = item; } else if (genericTypeDefinition == typeof(ICollection<>)) { hasICollectionGeneric = true; arrayItemType = item.GetGenericArguments()[0]; iCollectionGenericType = item; } else if (genericTypeDefinition == typeof(IList<>)) { hasIListGeneric = true; arrayItemType = item.GetGenericArguments()[0]; iListGenericType = item; } } else if (item == typeof(ICollection)) hasICollection = true; else if (item == typeof(IList)) hasIList = true; } if (hasIListGeneric) { var ctor = t.GetDefaultNoArgCtorOrAppointTypeCtor(iListGenericType); if (ctor == null) { foreach (var item in t.GetConstructors()) { if (item.GetParameters().Length == 1) { var firstCtor = item.GetParameters()[0]; if (firstCtor.ParameterType.IsArray || TypeIsCollection(firstCtor.ParameterType) != null) { return () => BuildFactory.Create(SerializerBuildTypeEnum.IListGeneric); } } } } else if (ctor.GetParameters().Length == 0) { return () => BuildFactory.Create(SerializerBuildTypeEnum.IListGeneric); } else return () => BuildFactory.Create(SerializerBuildTypeEnum.IListGeneric); } if (hasICollectionGeneric) { var ctor = t.GetDefaultNoArgCtorOrAppointTypeCtor(iCollectionGenericType); if (ctor == null) { foreach (var item in t.GetConstructors()) { if (item.GetParameters().Length == 1) { var firstCtor = item.GetParameters()[0]; if (firstCtor.ParameterType.IsArray || TypeIsCollection(firstCtor.ParameterType) != null) { return () => BuildFactory.Create(SerializerBuildTypeEnum.IEnumerableGeneric); } } } } else if (ctor.GetParameters().Length == 0) { return () => BuildFactory.Create(SerializerBuildTypeEnum.IEnumerableGeneric); } else return () => BuildFactory.Create(SerializerBuildTypeEnum.IEnumerableGeneric); } if (hasIEnumerableGeneric && hasICollection) { var ctor = t.GetAppointTypeCtor(iEnumerableGenericType); if (ctor == null) { foreach (var item in t.GetConstructors()) { if (item.GetParameters().Length == 1) { var firstCtor = item.GetParameters()[0]; if (firstCtor.ParameterType.IsArray || TypeIsCollection(firstCtor.ParameterType) != null) { return () => BuildFactory.Create(SerializerBuildTypeEnum.IEnumerableGeneric); } } } } else return () => BuildFactory.Create(SerializerBuildTypeEnum.IEnumerableGeneric); } if (hasIList) { var ctor = t.GetDefaultNoArgCtorOrAppointTypeCtor(typeof(IList)); if (ctor == null) { foreach (var item in t.GetConstructors()) { if (item.GetParameters().Length == 1) { var firstCtor = item.GetParameters()[0]; if (firstCtor.ParameterType.IsArray || TypeIsCollection(firstCtor.ParameterType) != null) { return () => (obj, handler) => SpecialConditions.WriteCollection((IEnumerable)obj, handler); } } } } else if (ctor.GetParameters().Length == 0) { return () => (obj, handler) => SpecialConditions.WriteCollection((IEnumerable)obj, handler); } else return () => (obj, handler) => SpecialConditions.WriteCollection((IEnumerable)obj, handler); } if (hasICollection) { var ctor = t.GetAppointTypeCtor(typeof(ICollection)); if (ctor == null) { foreach (var item in t.GetConstructors()) { if (item.GetParameters().Length == 1) { var firstCtor = item.GetParameters()[0]; if (firstCtor.ParameterType.IsArray || TypeIsCollection(firstCtor.ParameterType) != null) { return () => (obj, handler) => SpecialConditions.WriteCollection((IEnumerable)obj, handler); } } } } else return () => (obj, handler) => SpecialConditions.WriteCollection((IEnumerable)obj, handler); } return null; } private static Func> TypeIsSpecial(Type t) { if (t.IsGenericType) { var genericTypeDefinition = t.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(KeyValuePair<,>)) { var keyType = t.GetGenericArguments()[0]; return () => IsWrongKeyType(keyType) ?? BuildFactory.Create(SerializerBuildTypeEnum.KeyValuePair); } if (genericTypeDefinition == typeof(Nullable<>)) return () => BuildFactory.Create(SerializerBuildTypeEnum.Nullable); if (genericTypeDefinition == typeof(Lazy<>)) return () => BuildFactory.Create(SerializerBuildTypeEnum.Lazy); if (genericTypeDefinition == typeof(Lookup<,>)) { } if (genericTypeDefinition == typeof(ILookup<,>)) { } } return null; } private static Action IsArray(Type t) { if (t.IsArray) { if (t.GetArrayRank() == 1) return BuildFactory.Create(SerializerBuildTypeEnum.IListGeneric); else return (obj, handler) => SpecialConditions.WriteCollection((IEnumerable)obj, handler); } return null; } private static Action IsLoadDynamic(Type t) { if (t.IsAnonymousType()) return (a, b) => SpecialConditions.WriteDynamic(a, b); return null; } private static Action IsEnum(Type t) { if (t.IsEnum) return GenerateLambdaCallWithTypeConvert(SpecialConditions._WriteEnum, typeof(Enum)); return null; } private static Action IsWrongKeyType(Type keyType) { if (keyType.IsWrongKey()) return BuildFactory.Create(SerializerBuildTypeEnum.WrongGenericKey); return null; } private static Action GenerateLambdaCall(MethodInfo method) { ParameterExpression objArg = Expression.Parameter(typeof(T), "instance"); ParameterExpression handlerArg = Expression.Parameter(typeof(JsonSerializerHandler), "handler"); var body = Expression.Call(method, objArg, handlerArg); return Expression.Lambda>(body, objArg, handlerArg).Compile(); } private static Action GenerateLambdaCallWithTypeConvert(MethodInfo method, Type t) { ParameterExpression objArg = Expression.Parameter(typeof(T), "instance"); ParameterExpression handlerArg = Expression.Parameter(typeof(JsonSerializerHandler), "handler"); var body = Expression.Call(method, Expression.Convert(objArg, t), handlerArg); return Expression.Lambda>(body, objArg, handlerArg).Compile(); } } }