complete support MessagePackFormatterAtribute per member
This commit is contained in:
Родитель
1bf4c109d3
Коммит
faa9a7c544
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче