complete support MessagePackFormatterAtribute per member

This commit is contained in:
neuecc 2017-10-10 02:45:07 +09:00
Родитель 1bf4c109d3
Коммит faa9a7c544
4 изменённых файлов: 204 добавлений и 56 удалений

Просмотреть файл

@ -1,4 +1,5 @@
using MessagePack;
using MessagePack.Formatters;
using MessagePack.Internal;
using MessagePack.Resolvers;
using SharedData;
@ -33,7 +34,7 @@ namespace DynamicCodeDumper
//DynamicObjectResolver.Instance.GetFormatter<SimlpeStringKeyData2>();
//DynamicObjectResolver.Instance.GetFormatter<StringKeySerializerTarget>();
//DynamicObjectResolver.Instance.GetFormatter<LongestString>();
var f = DynamicObjectResolver.Instance.GetFormatter<Callback2_2>();
var f = DynamicObjectResolver.Instance.GetFormatter<MyClass>();
//DynamicObjectResolver.Instance.GetFormatter<StringKeySerializerTargetBinary>();
//DynamicObjectResolver.Instance.GetFormatter<Callback1>();
//DynamicObjectResolver.Instance.GetFormatter<Callback1_2>();
@ -55,7 +56,7 @@ namespace DynamicCodeDumper
//DynamicContractlessObjectResolver.Instance.GetFormatter<EntityBase>();
byte[] b = null;
f.Serialize(ref b, 0, default(Callback2_2), null);
f.Serialize(ref b, 0, new MyClass { MyProperty1 = 100, MyProperty2 = "foo" }, null);
}
catch (Exception ex)
@ -95,6 +96,42 @@ namespace DynamicCodeDumper
}
}
}
[MessagePackObject]
public class MyClass
{
[Key(0)]
[MessagePackFormatter(typeof(Int_x10Formatter))]
public int MyProperty1 { get; set; }
[Key(1)]
[MessagePackFormatter(typeof(String_x2Formatter))]
public string MyProperty2 { get; set; }
}
public class Int_x10Formatter : IMessagePackFormatter<int>
{
public int Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
{
return MessagePackBinary.ReadInt32(bytes, offset, out readSize) * 10;
}
public int Serialize(ref byte[] bytes, int offset, int value, IFormatterResolver formatterResolver)
{
return MessagePackBinary.WriteInt32(ref bytes, offset, value * 10);
}
}
public class String_x2Formatter : IMessagePackFormatter<string>
{
public string Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
{
var s = MessagePackBinary.ReadString(bytes, offset, out readSize);
return s + s;
}
public int Serialize(ref byte[] bytes, int offset, string value, IFormatterResolver formatterResolver)
{
return MessagePackBinary.WriteString(ref bytes, offset, value + value);
}
}
[MessagePackObject(true)]
public struct Callback2_2 : IMessagePackSerializationCallbackReceiver

Просмотреть файл

@ -249,11 +249,13 @@ namespace MessagePack.Internal
}, (index, member) =>
{
FieldInfo fi;
if (!customFormatterLookup.TryGetValue(member, out fi)) return false;
if (!customFormatterLookup.TryGetValue(member, out fi)) return null;
il.EmitLoadThis();
il.EmitLdfld(fi);
return true;
return () =>
{
il.EmitLoadThis();
il.EmitLdfld(fi);
};
}, 1);
}
@ -322,14 +324,16 @@ namespace MessagePack.Internal
il.EmitLdarg(0);
}, (index, member) =>
{
if (serializeCustomFormatters.Count == 0) return false;
if (serializeCustomFormatters[index] == null) return false;
if (serializeCustomFormatters.Count == 0) return null;
if (serializeCustomFormatters[index] == null) return null;
il.EmitLdarg(1); // read object[]
il.EmitLdc_I4(index);
il.Emit(OpCodes.Ldelem_Ref); // object
il.Emit(OpCodes.Castclass, serializeCustomFormatters[index].GetType());
return true;
return () =>
{
il.EmitLdarg(1); // read object[]
il.EmitLdc_I4(index);
il.Emit(OpCodes.Ldelem_Ref); // object
il.Emit(OpCodes.Castclass, serializeCustomFormatters[index].GetType());
};
}, 2); // 0, 1 is parameter.
}
@ -383,59 +387,55 @@ namespace MessagePack.Internal
static Dictionary<ObjectSerializationInfo.EmittableMember, FieldInfo> BuildCustomFormatterField(TypeBuilder builder, ObjectSerializationInfo info, ILGenerator il)
{
// TODO
Dictionary<ObjectSerializationInfo.EmittableMember, FieldInfo> dict = new Dictionary<ObjectSerializationInfo.EmittableMember, FieldInfo>();
//foreach (var item in info.Members.Where(x => x.IsReadable || x.IsWritable))
//{
// var attr = item.GetMessagePackFormatterAttribtue();
// if (attr != null)
// {
// // var attr = typeof(Foo).Get .GetCustomAttribute<T>(true);
// // this.f = Activator.CreateInstance(attr.FormatterType, attr.Arguments);
foreach (var item in info.Members.Where(x => x.IsReadable || x.IsWritable))
{
var attr = item.GetMessagePackFormatterAttribtue();
if (attr != null)
{
var f = builder.DefineField(item.Name + "_formatter", attr.FormatterType, FieldAttributes.Private | FieldAttributes.InitOnly);
// var f = builder.DefineField(item.Name + "_formatter", attr.FormatterType, FieldAttributes.Private | FieldAttributes.InitOnly);
var bindingFlags = (int)(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
// // var bindingFlags = (int)(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var attrVar = il.DeclareLocal(typeof(MessagePackFormatterAttribute));
// var attrVar = il.DeclareLocal(typeof(MessagePackFormatterAttribute));
il.Emit(OpCodes.Ldtoken, info.Type);
il.EmitCall(EmitInfo.GetTypeFromHandle);
il.Emit(OpCodes.Ldstr, item.Name);
il.EmitLdc_I4(bindingFlags);
if (item.IsProperty)
{
il.EmitCall(EmitInfo.TypeGetProperty);
}
else
{
il.EmitCall(EmitInfo.TypeGetField);
}
// il.Emit(OpCodes.Ldtoken, info.Type);
// il.EmitCall(EmitInfo.GetTypeFromHandle);
// il.Emit(OpCodes.Ldstr, item.Name);
// il.EmitLdc_I4(bindingFlags);
// if (item.IsProperty)
// {
// il.EmitCall(EmitInfo.TypeGetProperty);
// }
// else
// {
// il.EmitCall(EmitInfo.TypeGetField);
// }
il.EmitTrue();
il.EmitCall(EmitInfo.GetCustomAttributeMessagePackFormatterAttribute);
il.EmitStloc(attrVar);
// il.EmitTrue();
// il.EmitCall(EmitInfo.GetCustomAttributeJsonFormatterAttribute);
// il.EmitStloc(attrVar);
il.EmitLoadThis();
// il.EmitLoadThis();
il.EmitLdloc(attrVar);
il.EmitCall(EmitInfo.MessagePackFormatterAttr.FormatterType);
il.EmitLdloc(attrVar);
il.EmitCall(EmitInfo.MessagePackFormatterAttr.Arguments);
il.EmitCall(EmitInfo.ActivatorCreateInstance);
// il.EmitLdloc(attrVar);
// il.EmitCall(EmitInfo.JsonFormatterAttr.FormatterType);
// il.EmitLdloc(attrVar);
// il.EmitCall(EmitInfo.JsonFormatterAttr.Arguments);
// il.EmitCall(EmitInfo.ActivatorCreateInstance);
il.Emit(OpCodes.Castclass, attr.FormatterType);
il.Emit(OpCodes.Stfld, f);
// il.Emit(OpCodes.Castclass, attr.FormatterType);
// il.Emit(OpCodes.Stfld, f);
// dict.Add(item, f);
// }
//}
dict.Add(item, f);
}
}
return dict;
}
// int Serialize([arg:1]ref byte[] bytes, [arg:2]int offset, [arg:3]T value, [arg:4]IFormatterResolver formatterResolver);
static void BuildSerialize(Type type, ObjectSerializationInfo info, ILGenerator il, Action emitStringByteKeys, Func<int, ObjectSerializationInfo.EmittableMember, bool> tryEmitLoadCustomFormatter, int firstArgIndex)
static void BuildSerialize(Type type, ObjectSerializationInfo info, ILGenerator il, Action emitStringByteKeys, Func<int, ObjectSerializationInfo.EmittableMember, Action> tryEmitLoadCustomFormatter, int firstArgIndex)
{
var argBytes = new ArgumentField(il, firstArgIndex);
var argOffset = new ArgumentField(il, firstArgIndex + 1);
@ -596,19 +596,23 @@ namespace MessagePack.Internal
argOffset.EmitStore();
}
static void EmitSerializeValue(ILGenerator il, TypeInfo type, ObjectSerializationInfo.EmittableMember member, int index, Func<int, ObjectSerializationInfo.EmittableMember, bool> tryEmitLoadCustomFormatter, ArgumentField argBytes, ArgumentField argOffset, ArgumentField argValue, ArgumentField argResolver)
static void EmitSerializeValue(ILGenerator il, TypeInfo type, ObjectSerializationInfo.EmittableMember member, int index, Func<int, ObjectSerializationInfo.EmittableMember, Action> tryEmitLoadCustomFormatter, ArgumentField argBytes, ArgumentField argOffset, ArgumentField argValue, ArgumentField argResolver)
{
var t = member.Type;
if (tryEmitLoadCustomFormatter(index, member))
var emitter = tryEmitLoadCustomFormatter(index, member);
if (emitter != null)
{
EmitOffsetPlusEqual(il, () =>
{
emitter();
}, () =>
{
argValue.EmitLoad();
member.EmitLoadValue(il);
argResolver.EmitLoad();
il.EmitCall(typeof(IMessagePackFormatter<>).MakeGenericType(t).GetRuntimeMethod("Serialize", new[] { refByte, typeof(int), t, typeof(IFormatterResolver) }));
}, argBytes, argOffset);
}
else if (IsOptimizeTargetType(t))
@ -1110,8 +1114,16 @@ typeof(int), typeof(int) });
internal static class EmitInfo
{
public static readonly MethodInfo GetTypeFromHandle = ExpressionUtility.GetMethodInfo(() => Type.GetTypeFromHandle(default(RuntimeTypeHandle)));
//public static readonly MethodInfo TypeGetProperty = ExpressionUtility.GetMethodInfo((Type t) => t.GetProperty(default(string), default(BindingFlags)));
//public static readonly MethodInfo TypeGetField = ExpressionUtility.GetMethodInfo((Type t) => t.GetField(default(string), default(BindingFlags)));
public static readonly MethodInfo TypeGetProperty = ExpressionUtility.GetMethodInfo((Type t) => t.GetProperty(default(string), default(BindingFlags)));
public static readonly MethodInfo TypeGetField = ExpressionUtility.GetMethodInfo((Type t) => t.GetField(default(string), default(BindingFlags)));
public static readonly MethodInfo GetCustomAttributeMessagePackFormatterAttribute = ExpressionUtility.GetMethodInfo(() => CustomAttributeExtensions.GetCustomAttribute<MessagePackFormatterAttribute>(default(MemberInfo), default(bool)));
public static readonly MethodInfo ActivatorCreateInstance = ExpressionUtility.GetMethodInfo(() => Activator.CreateInstance(default(Type), default(object[])));
internal static class MessagePackFormatterAttr
{
internal static readonly MethodInfo FormatterType = ExpressionUtility.GetPropertyInfo((MessagePackFormatterAttribute attr) => attr.FormatterType).GetGetMethod();
internal static readonly MethodInfo Arguments = ExpressionUtility.GetPropertyInfo((MessagePackFormatterAttribute attr) => attr.Arguments).GetGetMethod();
}
}
class DeserializeInfo

Просмотреть файл

@ -109,6 +109,7 @@
<Compile Include="CollectionTest.cs" />
<Compile Include="DataContractTest.cs" />
<Compile Include="DynamicObjectFallbackTest.cs" />
<Compile Include="MessagePackFormatterPerField.cs" />
<Compile Include="NewGuidFormatterTest.cs" />
<Compile Include="NonGenericCollectionTest.cs" />
<Compile Include="StreamStrictTest.cs" />

Просмотреть файл

@ -0,0 +1,98 @@
using MessagePack.Formatters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace MessagePack.Tests
{
public class MessagePackFormatterPerFieldTest
{
[MessagePackObject]
public class MyClass
{
[Key(0)]
[MessagePackFormatter(typeof(Int_x10Formatter))]
public int MyProperty1 { get; set; }
[Key(1)]
public int MyProperty2 { get; set; }
[Key(2)]
[MessagePackFormatter(typeof(String_x2Formatter))]
public string MyProperty3 { get; set; }
[Key(3)]
public string MyProperty4 { get; set; }
}
[MessagePackObject]
public struct MyStruct
{
[Key(0)]
[MessagePackFormatter(typeof(Int_x10Formatter))]
public int MyProperty1 { get; set; }
[Key(1)]
public int MyProperty2 { get; set; }
[Key(2)]
[MessagePackFormatter(typeof(String_x2Formatter))]
public string MyProperty3 { get; set; }
[Key(3)]
public string MyProperty4 { get; set; }
}
public class Int_x10Formatter : IMessagePackFormatter<int>
{
public int Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
{
return MessagePackBinary.ReadInt32(bytes, offset, out readSize) * 10;
}
public int Serialize(ref byte[] bytes, int offset, int value, IFormatterResolver formatterResolver)
{
return MessagePackBinary.WriteInt32(ref bytes, offset, value * 10);
}
}
public class String_x2Formatter : IMessagePackFormatter<string>
{
public string Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
{
var s = MessagePackBinary.ReadString(bytes, offset, out readSize);
return s + s;
}
public int Serialize(ref byte[] bytes, int offset, string value, IFormatterResolver formatterResolver)
{
return MessagePackBinary.WriteString(ref bytes, offset, value + value);
}
}
[Fact]
public void FooBar()
{
{
var bin = MessagePack.MessagePackSerializer.Serialize(new MyClass { MyProperty1 = 100, MyProperty2 = 9, MyProperty3 = "foo", MyProperty4 = "bar" });
var json = MessagePackSerializer.ToJson(bin);
json.Is("[1000,9,\"foofoo\",\"bar\"]");
var r2 = MessagePackSerializer.Deserialize<MyClass>(bin);
r2.MyProperty1.Is(10000);
r2.MyProperty2.Is(9);
r2.MyProperty3.Is("foofoofoofoo");
r2.MyProperty4.Is("bar");
}
{
var bin = MessagePack.MessagePackSerializer.Serialize(new MyStruct { MyProperty1 = 100, MyProperty2 = 9, MyProperty3 = "foo", MyProperty4 = "bar" });
var json = MessagePackSerializer.ToJson(bin);
json.Is("[1000,9,\"foofoo\",\"bar\"]");
var r2 = MessagePackSerializer.Deserialize<MyStruct>(bin);
r2.MyProperty1.Is(10000);
r2.MyProperty2.Is(9);
r2.MyProperty3.Is("foofoofoofoo");
r2.MyProperty4.Is("bar");
}
}
}
}