#if !UNITY_METRO using System; using MessagePack.Formatters; using MessagePack.Internal; using System.Reflection; using System.Reflection.Emit; namespace MessagePack.Resolvers { /// /// EnumResolver by dynamic code generation, serialized underlying type. /// public sealed class DynamicEnumResolver : IFormatterResolver { public static readonly DynamicEnumResolver Instance = new DynamicEnumResolver(); const string ModuleName = "MessagePack.Resolvers.DynamicEnumResolver"; static readonly DynamicAssembly assembly; DynamicEnumResolver() { } static DynamicEnumResolver() { assembly = new DynamicAssembly(ModuleName); } #if NET_35 public AssemblyBuilder Save() { return assembly.Save(); } #endif public IMessagePackFormatter GetFormatter() { return FormatterCache.formatter; } static class FormatterCache { public static readonly IMessagePackFormatter formatter; static FormatterCache() { var ti = typeof(T).GetTypeInfo(); if (ti.IsNullable()) { // build underlying type and use wrapped formatter. ti = ti.GenericTypeArguments[0].GetTypeInfo(); if (!ti.IsEnum) { return; } var innerFormatter = DynamicEnumResolver.Instance.GetFormatterDynamic(ti.AsType()); if (innerFormatter == null) { return; } formatter = (IMessagePackFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); return; } else if (!ti.IsEnum) { return; } var formatterTypeInfo = BuildType(typeof(T)); formatter = (IMessagePackFormatter)Activator.CreateInstance(formatterTypeInfo.AsType()); } } static TypeInfo BuildType(Type enumType) { var underlyingType = Enum.GetUnderlyingType(enumType); var formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(enumType); var typeBuilder = assembly.ModuleBuilder.DefineType("MessagePack.Formatters." + enumType.FullName.Replace(".", "_") + "Formatter", TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType }); // int Serialize(ref byte[] bytes, int offset, T value, IFormatterResolver formatterResolver); { var method = typeBuilder.DefineMethod("Serialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, typeof(int), new Type[] { typeof(byte[]).MakeByRefType(), typeof(int), enumType, typeof(IFormatterResolver) }); var il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_3); il.Emit(OpCodes.Call, typeof(MessagePackBinary).GetRuntimeMethod("Write" + underlyingType.Name, new[] { typeof(byte[]).MakeByRefType(), typeof(int), underlyingType })); il.Emit(OpCodes.Ret); } // T Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize); { var method = typeBuilder.DefineMethod("Deserialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, enumType, new Type[] { typeof(byte[]), typeof(int), typeof(IFormatterResolver), typeof(int).MakeByRefType() }); var il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_S, (byte)4); il.Emit(OpCodes.Call, typeof(MessagePackBinary).GetRuntimeMethod("Read" + underlyingType.Name, new[] { typeof(byte[]), typeof(int), typeof(int).MakeByRefType() })); il.Emit(OpCodes.Ret); } return typeBuilder.CreateTypeInfo(); } } } #endif