Resolvers
IDictionaryResolver.cs
using Bssom.Serializer.BssMap;
using Bssom.Serializer.BssMap.KeyResolvers;
using Bssom.Serializer.Formatters;
using Bssom.Serializer.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
namespace Bssom.Serializer.Resolvers
{
///
/// 获取和生成具有IDictionary行为的类型的
/// Get and generate the type with IDictionary behavior
///
public clast IDictionaryResolver : IFormatterResolver
{
internal const string ModuleName = "Bssom.Serializer.Resolvers.IDictionaryResolver";
internal static readonly DynamicFormatterastembly Dynamicastembly;
///
/// The singleton instance that can be used.
///
public static readonly IDictionaryResolver Instance;
static IDictionaryResolver()
{
Instance = new IDictionaryResolver();
Dynamicastembly = new DynamicFormatterastembly(ModuleName);
}
public IBssomFormatter GetFormatter()
{
return FormatterCache.Formatter;
}
private static clast FormatterCache
{
public static readonly IBssomFormatter Formatter;
static FormatterCache()
{
Type t = typeof(T);
if (t == typeof(IDictionary))
{
Formatter = (IBssomFormatter)((IBssomFormatter)IDictionaryFormatter.Instance);
return;
}
if (TypeIsDictionary(t, out ConstructorInfo constructor, out bool typeIsGeneric, out Type genericTypeDefinition, out Type genericKeyType, out Type genericValueType))
{
if (typeIsGeneric && genericKeyType != typeof(object) && !BssMapKeyResolverProvider.TryGetBssMapKeyResolver(genericKeyType, out IBssMapKeyResolver keyConvert))
{
return;// throw BssomSerializationException.MapKeyTypeError();
}
TypeInfo buildType;
if (typeIsGeneric)
{
if (t.IsInterface)
{
buildType = IDictionaryFormatterTypeBuilder.BuildGenericIDictionaryInterfaceType(Dynamicastembly, t, genericTypeDefinition, genericKeyType, genericValueType);
}
else
{
buildType = IDictionaryFormatterTypeBuilder.BuildGenericIDictionaryImplementationType(Dynamicastembly, constructor, t, genericKeyType, genericValueType);
}
}
else
{
//impl IDictionary clast/struct
buildType = IDictionaryFormatterTypeBuilder.BuildIDictionaryImplementationType(Dynamicastembly, constructor, t);
}
Formatter = (IBssomFormatter)Activator.CreateInstance(buildType);
}
}
}
internal static bool TypeIsDictionary(Type t, out ConstructorInfo constructor, out bool typeIsGeneric, out Type genericTypeDefinition, out Type genericKeyType, out Type genericValueType)
{
constructor = null;
typeIsGeneric = false;
genericKeyType = null;
genericValueType = null;
genericTypeDefinition = null;
Type genericType = null;
bool hasIDictionaryGeneric = false;
bool hasIDictionary = false;
if (t.IsInterface)
{
if (t == typeof(IDictionary))
{
return true;
}
if (t.IsGenericType)
{
genericTypeDefinition = t.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(IDictionary) || genericTypeDefinition == typeof(IReadOnlyDictionary))
{
Type[] args = t.GetGenericArguments();
typeIsGeneric = true;
genericType = t;
genericKeyType = args[0];
genericValueType = args[1];
return true;
}
}
return false;
}
if (t.IsGenericType)
{
genericTypeDefinition = t.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(Dictionary) ||
genericTypeDefinition == typeof(SortedList))
{
constructor = t.GetAppointTypeCtor(typeof(int));
typeIsGeneric = true;
Type[] args = t.GetGenericArguments();
genericKeyType = args[0];
genericValueType = args[1];
return true;
}
}
IEnumerable intserfaces = t.GetInterfaces();
foreach (Type item in intserfaces)
{
if (item.IsGenericType)
{
genericTypeDefinition = item.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(IDictionary) ||
genericTypeDefinition == typeof(IReadOnlyDictionary))
{
genericType = item;
Type[] args = item.GetGenericArguments();
genericKeyType = args[0];
genericValueType = args[1];
hasIDictionaryGeneric = true;
break;
}
}
else if (item == typeof(IDictionary))
{
hasIDictionary = true;
}
}
if (hasIDictionaryGeneric)
{
typeIsGeneric = true;
//clast :IDictionary
// ctor( ReadOnlyDic )
// ctor( Dictionary )
if (TryGetConstructorInfo(t, genericKeyType, genericValueType, true, out constructor))
{
return true;
}
}
else if (hasIDictionary)
{
constructor = t.GetDefaultNoArgCtorOrAppointTypeCtor(typeof(IDictionary));
if (constructor != null)
{
return true;
}
}
return false;
}
private static bool TryGetConstructorInfo(Type targetType, Type genericKeyType, Type genericValueType, bool isFindEmptyCtor, out ConstructorInfo constructor)
{
constructor = null;
foreach (ConstructorInfo item in targetType.GetConstructors())
{
ParameterInfo[] paras = item.GetParameters();
if (isFindEmptyCtor)
{
if (paras.Length == 0)
{
constructor = item;
return true;
}
}
if (constructor != null)
{
continue;
}
if (paras.Length == 1)
{
Type ctorArgType = paras[0].ParameterType;
if (targetType == ctorArgType)
{
continue;
}
if (TypeIsDictionary(ctorArgType, out ConstructorInfo cons, out bool tIsGener, out Type generTypeDefine, out Type generKeyType, out Type generValueType))
{
if (tIsGener == false ||
(generKeyType == genericKeyType && generValueType == genericValueType))
{
constructor = item;
if (!isFindEmptyCtor)
{
return true;
}
}
}
}
}
return constructor != null;
}
}
}
namespace Bssom.Serializer.Internal
{
internal static clast IDictionaryFormatterTypeBuilder
{
//apply to IDictionary/IReadOnlyDictionary
public static TypeInfo BuildGenericIDictionaryInterfaceType(DynamicFormatterastembly astembly, Type type, Type genericTypeDefine, Type genericKeyType, Type genericValueType)
{
DEBUG.astert(genericTypeDefine == typeof(IDictionary) || genericTypeDefine == typeof(IReadOnlyDictionary));
TypeBuilder typeBuilder = astembly.DefineFormatterType(type);
MethodBuilder serializeMethod = TypeBuildHelper.DefineSerializeMethod(typeBuilder, type);
TypeBuildHelper.CallOneMethodInSerialize(serializeMethod, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.SerializeGenericDictionary), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(new Type[] { genericKeyType, genericValueType }));
MethodBuilder deserializeMethod = TypeBuildHelper.DefineDeserializeMethod(typeBuilder, type);
if (genericTypeDefine == typeof(IDictionary))
{
TypeBuildHelper.CallOneMethodInDeserialize(deserializeMethod, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.GenericDictionaryDeserialize), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(new Type[] { genericKeyType, genericValueType }));
}
else
{
TypeBuildHelper.CallOneMethodInDeserialize(deserializeMethod, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.ReadOnlyGenericDictionaryDeserialize), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(new Type[] { genericKeyType, genericValueType }));
}
MethodBuilder sizeMethod = TypeBuildHelper.DefineSizeMethod(typeBuilder, type);
TypeBuildHelper.CallOneMethodInSize(sizeMethod, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.SizeGenericDictionary), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(genericKeyType, genericValueType));
return typeBuilder.CreateTypeInfo();
}
//apply to IDictionary/IReadOnlyDictionary impl
public static TypeInfo BuildGenericIDictionaryImplementationType(DynamicFormatterastembly astembly, ConstructorInfo constructor, Type type, Type genericKeyType, Type genericValueType)
{
TypeBuilder typeBuilder = astembly.DefineFormatterType(type);
MethodBuilder serializeMethod = TypeBuildHelper.DefineSerializeMethod(typeBuilder, type);
TypeBuildHelper.CallOneMethodInSerialize(serializeMethod, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.SerializeGenericDictionary), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(new Type[] { genericKeyType, genericValueType }));
MethodBuilder deserializeMethod = TypeBuildHelper.DefineDeserializeMethod(typeBuilder, type);
ParameterInfo[] args = constructor.GetParameters();
Type dynamicCacheType = typeof(IDictionaryDynamicDelegateCache).MakeGenericType(type);
if (args.Length == 0)
{
MethodInfo methodinfo = dynamicCacheType.GetMethod(nameof(IDictionaryDynamicDelegateCache.GenerateDeserializeWithGenericDictEmptyCtor));
methodinfo.Invoke(null, new object[] { constructor, genericKeyType, genericValueType });
}
else
{
DEBUG.astert(args.Length == 1);
if (args[0].ParameterType == typeof(int))
{
MethodInfo methodinfo = dynamicCacheType.GetMethod(nameof(IDictionaryDynamicDelegateCache.GenerateDeserializeWithGenericDictCapacityCtor));
methodinfo.Invoke(null, new object[] { constructor, genericKeyType, genericValueType });
}
else
{
MethodInfo methodinfo = dynamicCacheType.GetMethod(nameof(IDictionaryDynamicDelegateCache.GenerateInjectCtor));
methodinfo.Invoke(null, new object[] { constructor, args[0].ParameterType });
}
}
TypeBuildHelper.CallDeserializeDelegate(deserializeMethod, type, dynamicCacheType.GetField(nameof(IDictionaryDynamicDelegateCache.Deserialize), BindingFlags.Public | BindingFlags.Static));
MethodBuilder sizeMethod = TypeBuildHelper.DefineSizeMethod(typeBuilder, type);
TypeBuildHelper.CallOneMethodInSize(sizeMethod, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.SizeGenericDictionary), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(genericKeyType, genericValueType));
return typeBuilder.CreateTypeInfo();
}
//apply to IDictionary impl
public static TypeInfo BuildIDictionaryImplementationType(DynamicFormatterastembly astembly, ConstructorInfo constructor, Type type)
{
TypeBuilder typeBuilder = astembly.DefineFormatterType(type);
MethodBuilder serializeMethod = TypeBuildHelper.DefineSerializeMethod(typeBuilder, type);
TypeBuildHelper.CallOneMethodInSerialize(serializeMethod, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.SerializeIDictionary), BindingFlags.Public | BindingFlags.Static));
MethodBuilder deserializeMethod = TypeBuildHelper.DefineDeserializeMethod(typeBuilder, type);
ParameterInfo[] args = constructor.GetParameters();
Type dynamicCacheType = typeof(IDictionaryDynamicDelegateCache).MakeGenericType(type);
if (args.Length == 1)
{
DEBUG.astert(args[0].ParameterType == typeof(IDictionary));
//return new T(IDictionaryFormatter.Deserialize)
MethodInfo methodinfo = dynamicCacheType.GetMethod(nameof(IDictionaryDynamicDelegateCache.GenerateInjectCtor));
methodinfo.Invoke(null, new object[] { constructor, args[0].ParameterType });
}
else
{
MethodInfo methodinfo = dynamicCacheType.GetMethod(nameof(IDictionaryDynamicDelegateCache.GenerateDeserializeWithIDictionaryEmptyCtor));
methodinfo.Invoke(null, new object[] { });
}
TypeBuildHelper.CallDeserializeDelegate(deserializeMethod, type, dynamicCacheType.GetField(nameof(IDictionaryDynamicDelegateCache.Deserialize), BindingFlags.Public | BindingFlags.Static));
MethodBuilder sizeMethod = TypeBuildHelper.DefineSizeMethod(typeBuilder, type);
TypeBuildHelper.CallOneMethodInSize(sizeMethod, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.SizeIDictionary), BindingFlags.Public | BindingFlags.Static));
return typeBuilder.CreateTypeInfo();
}
}
internal static clast IDictionaryDynamicDelegateCache
{
public static Deserialize Deserialize;
public static void GenerateDeserializeWithGenericDictEmptyCtor(ConstructorInfo constructor, Type keyType, Type valueType)
{
GenerateDeserializeWithGenericDictCore(keyType, valueType, (count) => Expression.New(constructor));
}
public static void GenerateDeserializeWithGenericDictCapacityCtor(ConstructorInfo constructor, Type keyType, Type valueType)
{
GenerateDeserializeWithGenericDictCore(keyType, valueType, (count) => Expression.New(constructor, count));
}
private static void GenerateDeserializeWithGenericDictCore(Type keyType, Type valueType, Func ctor)
{
/*
var map = MapFormatterHelper.Deserialize(ref reader,ref context);
if (map == null)
return null;
context.option.Security.DepthStep(ref reader);
T t = new T();/new T(map.Count)
Deserialize(IEnumerable pair,(ICollection)t);
reader = map.Reader; context = map.Context;
reader.Seek(map.EndPos);
context.Depth--;
return t;
*/
ArrayPack ary = new ArrayPack(10);
Type t = typeof(T);
LabelTarget returnTarget = Expression.Label(t, "returnLable");
ParameterExpression map = Expression.Variable(typeof(IMapDataSource).MakeGenericType(keyType, valueType));
//map = MapFormatterHelper.Deserialize(ref reader,ref context);
ary.Add(Expression.astign(map, CommonExpressionMeta.Call_MapFormatterHelper_Deserialize(keyType, valueType)));
//if (map == null)
// goto label;
ary.Add(Expression.IfThen(Expression.Equal(map, Expression.Constant(null, map.Type)), Expression.Return(returnTarget, Expression.Default(t))));
//context.option.Security.DepthStep(ref reader);
ary.Add(CommonExpressionMeta.Call_DeserializeContext_Option_Security_DepthStep);
//T t = ctor(map.Count);
ParameterExpression instance = Expression.Variable(t);
ary.Add(Expression.astign(instance, ctor(Expression.Property(map, nameof(BssMapObjMarshalReader.Count)))));
//MapFormatterHelper.FillData(map,(ICollection)t)
ary.Add(Expression.Call(null, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.FillGenericIDictionaryData), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(keyType, valueType), map, Expression.Convert(instance, typeof(ICollection).MakeGenericType(typeof(KeyValuePair).MakeGenericType(keyType, valueType)))));
//reader = map.Reader; context = map.Context;
ary.Add(CommonExpressionMeta.Block_MapReaderAndContextastignLocalReaderAndContext(map));
//reader.Seek(map.EndPos);
ary.Add(CommonExpressionMeta.Call_Reader_BufferSeek(Expression.Property(map, nameof(IMapDataSource.EndPosition))));
//context.Depth--;
ary.Add(CommonExpressionMeta.Call_DeserializeContext_Depth_Decrementastign);
//return t;
ary.Add(Expression.Return(returnTarget, instance));
//label default(T)
ary.Add(Expression.Label(returnTarget, instance));
BlockExpression block = Expression.Block(new ParameterExpression[] { map, instance }, ary.GetArray());
Deserialize = Expression.Lambda(block, CommonExpressionMeta.Par_Reader, CommonExpressionMeta.Par_DeserializeContext).Compile();
}
public static void GenerateDeserializeWithIDictionaryEmptyCtor()
{
/*
var map = MapFormatterHelper.Deserialize(ref reader,ref context);
if (map == null)
return null;
context.option.Security.DepthStep(ref reader);
T t = new T();
Deserialize(IEnumerable pair,(ICollection)t);
reader = map.Reader; context = map.Context;
reader.Seek(map.EndPos);
context.Depth--;
return t;
*/
ArrayPack ary = new ArrayPack(10);
Type t = typeof(T);
LabelTarget returnTarget = Expression.Label(t, "returnLable");
ParameterExpression map = Expression.Variable(typeof(IMapDataSource).MakeGenericType(typeof(object), typeof(object)));
//map = MapFormatterHelper.Deserialize(ref reader,ref context);
ary.Add(Expression.astign(map, CommonExpressionMeta.Call_MapFormatterHelper_Deserialize(typeof(object), typeof(object))));
//if (map == null)
// goto label;
ary.Add(Expression.IfThen(Expression.Equal(map, Expression.Constant(null, map.Type)), Expression.Return(returnTarget, Expression.Default(t))));
//context.option.Security.DepthStep(ref reader);
ary.Add(CommonExpressionMeta.Call_DeserializeContext_Option_Security_DepthStep);
//T t = new T();
ParameterExpression instance = Expression.Variable(t);
ary.Add(Expression.astign(instance, Expression.New(t)));
//MapFormatterHelper.FillData(map,(IDictionary)t)
ary.Add(Expression.Call(null, typeof(MapFormatterHelper).GetMethod(nameof(MapFormatterHelper.FillIDictionaryData), BindingFlags.Public | BindingFlags.Static), map, Expression.Convert(instance, typeof(IDictionary))));
//reader = map.Reader; context = map.Context;
ary.Add(CommonExpressionMeta.Block_MapReaderAndContextastignLocalReaderAndContext(map));
//reader.Seek(map.EndPos);
ary.Add(CommonExpressionMeta.Call_Reader_BufferSeek(Expression.Property(map, nameof(IMapDataSource.EndPosition))));
//context.Depth--;
ary.Add(CommonExpressionMeta.Call_DeserializeContext_Depth_Decrementastign);
//return t;
ary.Add(Expression.Return(returnTarget, instance));
//label default(T)
ary.Add(Expression.Label(returnTarget, instance));
BlockExpression block = Expression.Block(new ParameterExpression[] { map, instance }, ary.GetArray());
Deserialize = Expression.Lambda(block, CommonExpressionMeta.Par_Reader, CommonExpressionMeta.Par_DeserializeContext).Compile();
}
public static void GenerateInjectCtor(ConstructorInfo constructor, Type injectType)
{
Deserialize = Expression.Lambda(CommonExpressionMeta.GenerateInjectCtor(typeof(T), constructor, injectType), CommonExpressionMeta.Par_Reader, CommonExpressionMeta.Par_DeserializeContext).Compile();
}
}
}