2023-11-21 23:05:03 +08:00

463 lines
19 KiB
C#

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<T>
{
internal static Action<T, JsonSerializerHandler> Find()
{
Type t = typeof(T);
return FindTypeIsDefaultImplemented(t) ?? FindTypeIsMeetDefaultCondition(t) ?? FindTypeIsDefaultImplementedBaseType(t) ?? FindTypeIsDefaultImplementedInterface(t) ?? DefaultResolve(t);
}
private static Action<T, JsonSerializerHandler> FindTypeIsDefaultImplemented(Type t)
{
if (SerializerBootTable.Table.DefaultSameTypes.TryGetValue(t, out MethodInfo value))
return GenerateLambdaCall(value);
return null;
}
private static Action<T, JsonSerializerHandler> FindTypeIsMeetDefaultCondition(Type t)
{
return IsLoadDynamic(t) ?? IsArray(t) ?? IsEnum(t);
}
private static Action<T, JsonSerializerHandler> 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<T, JsonSerializerHandler> 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<T, JsonSerializerHandler> DefaultResolve(Type t)
{
Func<Action<T, JsonSerializerHandler>> func = TypeIsDictionary(t) ?? TypeIsCollection(t) ?? TypeIsSpecial(t);
if (func != null)
return func();
return BuildFactory.Create<T>(SerializerBuildTypeEnum.KeyValueObject);
}
private static Func<Action<T, JsonSerializerHandler>> TypeIsDictionary(Type t)
{
return TypeIsDictionaryInterface(t) ?? TypeIsDictionaryType(t);
}
private static Func<Action<T, JsonSerializerHandler>> 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<T>(SerializerBuildTypeEnum.IDictionaryGeneric);
}
return null;
}
private static Func<Action<T, JsonSerializerHandler>> 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<T>(SerializerBuildTypeEnum.IDictionaryGeneric);
}
}
}
}
else if (ctor.GetParameters().Length == 0)
{
return () => IsWrongKeyType(keyType) ?? BuildFactory.Create<T>(SerializerBuildTypeEnum.IDictionaryGeneric);
}
else
return () => IsWrongKeyType(keyType) ?? BuildFactory.Create<T>(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<Action<T, JsonSerializerHandler>> TypeIsCollection(Type t)
{
return TypeIsCollectionInterface(t) ?? TypeIsCollectionType(t);
}
private static Func<Action<T, JsonSerializerHandler>> 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<T>(SerializerBuildTypeEnum.IEnumerableGeneric);
}
}
return null;
}
private static Func<Action<T, JsonSerializerHandler>> 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<T>(SerializerBuildTypeEnum.IListGeneric);
}
}
}
}
else if (ctor.GetParameters().Length == 0)
{
return () => BuildFactory.Create<T>(SerializerBuildTypeEnum.IListGeneric);
}
else
return () => BuildFactory.Create<T>(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<T>(SerializerBuildTypeEnum.IEnumerableGeneric);
}
}
}
}
else if (ctor.GetParameters().Length == 0)
{
return () => BuildFactory.Create<T>(SerializerBuildTypeEnum.IEnumerableGeneric);
}
else
return () => BuildFactory.Create<T>(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<T>(SerializerBuildTypeEnum.IEnumerableGeneric);
}
}
}
}
else
return () => BuildFactory.Create<T>(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<Action<T, JsonSerializerHandler>> TypeIsSpecial(Type t)
{
if (t.IsGenericType)
{
var genericTypeDefinition = t.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(KeyValuePair<,>))
{
var keyType = t.GetGenericArguments()[0];
return () => IsWrongKeyType(keyType) ?? BuildFactory.Create<T>(SerializerBuildTypeEnum.KeyValuePair);
}
if (genericTypeDefinition == typeof(Nullable<>))
return () => BuildFactory.Create<T>(SerializerBuildTypeEnum.Nullable);
if (genericTypeDefinition == typeof(Lazy<>))
return () => BuildFactory.Create<T>(SerializerBuildTypeEnum.Lazy);
if (genericTypeDefinition == typeof(Lookup<,>))
{
}
if (genericTypeDefinition == typeof(ILookup<,>))
{
}
}
return null;
}
private static Action<T, JsonSerializerHandler> IsArray(Type t)
{
if (t.IsArray)
{
if (t.GetArrayRank() == 1)
return BuildFactory.Create<T>(SerializerBuildTypeEnum.IListGeneric);
else
return (obj, handler) => SpecialConditions.WriteCollection((IEnumerable)obj, handler);
}
return null;
}
private static Action<T, JsonSerializerHandler> IsLoadDynamic(Type t)
{
if (t.IsAnonymousType())
return (a, b) => SpecialConditions.WriteDynamic(a, b);
return null;
}
private static Action<T, JsonSerializerHandler> IsEnum(Type t)
{
if (t.IsEnum)
return GenerateLambdaCallWithTypeConvert(SpecialConditions._WriteEnum, typeof(Enum));
return null;
}
private static Action<T, JsonSerializerHandler> IsWrongKeyType(Type keyType)
{
if (keyType.IsWrongKey())
return BuildFactory.Create<T>(SerializerBuildTypeEnum.WrongGenericKey);
return null;
}
private static Action<T, JsonSerializerHandler> 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<Action<T, JsonSerializerHandler>>(body, objArg, handlerArg).Compile();
}
private static Action<T, JsonSerializerHandler> 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<Action<T, JsonSerializerHandler>>(body, objArg, handlerArg).Compile();
}
}
}