C#⾼性能⼆进制序列化
⼆进制序列化可以⽅便快捷的将对象进⾏持久化或者⽹络传输,并且体积⼩、性能⾼,应⽤⾯甚⾄还要⾼于json的序列化;开始之前,先来看看dotcore/dotne⾃带的⼆进制序列化:C#中对象序列化和反序列化⼀般是通过BinaryFormatter类来实现的⼆进制序列化、反序列化的。
BinaryFormatter序列化:
1 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 2
3 System.IO.MemoryStream memStream = new System.IO.MemoryStream();
4
5 serializer.Serialize(memStream, request);
BinaryFormatter反序列化:
1 memStream.Position=0;
2
3 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter deserializer =
4
5 new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
6
7 object newobj = deserializer.Deserialize(memStream);
8
9 memStream.Close();
10
11 return newobj;
⽤着多了就发现BinaryFormatter有很多地⽅不妥,下⾯就来数数这个序列化的“三宗罪”:
1.类名上⾯要加上[Serializable],不加不给序列化;正常的⽤法应该是序列化⼀个对象,不需的地⽅加上NonSerialized才合理吧;
2.序列化byte[]结果⾮常⼤,使⽤System.Text.Encoding.UTF8.GetString(bytes)查看下,发现⾥⾯有⼀⼤堆的元数据;对⽐看看google的protobuf,pb为什么在⽹络上应⽤的越来越多,这和他本⾝序列化完后体积⼩有着绝⼤部门的原因;
3.序列化对象需要完全⼀致,连类的命名空间都要相同,这点对于分⾯式开发的应⽤来说也是不可接受的;
既然BinaryFormatter不好⽤,那就只能动⼿⾃⾏实现⼀个解决上述问题的⼆进制序列化⽅案;⾸先去掉[Serializable]这个标签,接着主要是分析对象,并定义对象序列化后的数据结构;这⾥的想法是按长度加内容的⽅式来定义,举个例⼦:使⽤int作为长度,来保存⼀个int值,序列化完应该是:4,0,0,0,1,0,0,0这样的⼀组bytes,同理可以将int、short、long、float、double、datetime、enum、array、string、class、generic等按照这个格式进⾏序列化,这⾥主要使⽤的是BitConverter、反射等来实现序列化与反序列化;
序列化实现如下:
1public static byte[] Serialize(object param)
2 {
3 List<byte> datas = new List<byte>();
4
5var len = 0;
6
7byte[] data = null;
8
9if (param == null)
10 {
11 len = 0;
12 }
13else
14 {
15if (param is string)
16 {
17 data = Encoding.UTF8.GetBytes((string)param);
19else if (param is byte)
20 {
21 data = new byte[] { (byte)param };
22 }
23else if (param is bool)
24 {
25 data = BitConverter.GetBytes((bool)param);
26 }
27else if (param is short)
28 {
29 data = BitConverter.GetBytes((short)param);
30 }
31else if (param is int)
32 {
33 data = BitConverter.GetBytes((int)param);
34 }
35else if (param is long)
36 {
37 data = BitConverter.GetBytes((long)param);
38 }
39else if (param is float)
40 {
41 data = BitConverter.GetBytes((float)param);
42 }
43else if (param is double)
44 {
45 data = BitConverter.GetBytes((double)param);
46 }
47else if (param is DateTime)
48 {
49var str = "wl" + ((DateTime)param).Ticks;
50 data = Encoding.UTF8.GetBytes(str);
51 }
52else if (param is Enum)
53 {
54var enumValType = Enum.GetUnderlyingType(param.GetType()); 55
56if (enumValType == typeof(byte))
57 {
58 data = new byte[] { (byte)param };
59 }
60else if (enumValType == typeof(short))
61 {
62 data = BitConverter.GetBytes((Int16)param);
63 }
64else if (enumValType == typeof(int))
65 {
66 data = BitConverter.GetBytes((Int32)param);
67 }
68else
69 {
70 data = BitConverter.GetBytes((Int64)param);
71 }
72 }
73else if (param is byte[])
74 {
75 data = (byte[])param;
76 }
77else
78 {
79var type = param.GetType();
80
81typeof array
82if (type.IsGenericType || type.IsArray)
84if (TypeHelper.DicTypeStrs.Contains(type.Name))
85 data = SerializeDic((System.Collections.IDictionary)param);
86else if (TypeHelper.ListTypeStrs.Contains(type.Name) || type.IsArray) 87 data = SerializeList((System.Collections.IEnumerable)param);
88else
89 data = SerializeClass(param, type);
90 }
91else if (type.IsClass)
92 {
93 data = SerializeClass(param, type);
94 }
95
96 }
97if (data != null)
98 len = data.Length;
99 }
100 datas.AddRange(BitConverter.GetBytes(len));
101if (len > 0)
102 {
103 datas.AddRange(data);
104 }
105return datas.Count == 0 ? null : datas.ToArray();
106 }
View Code
反序列化实现如下:
1public static object Deserialize(Type type, byte[] datas, ref int offset)
2 {
3dynamic obj = null;
4
5var len = 0;
6
7byte[] data = null;
8
9 len = BitConverter.ToInt32(datas, offset);
10 offset += 4;
11if (len > 0)
12 {
13 data = new byte[len];
14 Buffer.BlockCopy(datas, offset, data, 0, len);
15 offset += len;
16
17if (type == typeof(string))
18 {
19 obj = Encoding.UTF8.GetString(data);
20 }
21else if (type == typeof(byte))
22 {
23 obj = (data);
24 }
25else if (type == typeof(bool))
26 {
27 obj = (BitConverter.ToBoolean(data, 0));
28 }
29else if (type == typeof(short))
30 {
31 obj = (BitConverter.ToInt16(data, 0));
32 }
33else if (type == typeof(int))
34 {
35 obj = (BitConverter.ToInt32(data, 0));
37else if (type == typeof(long))
38 {
39 obj = (BitConverter.ToInt64(data, 0));
40 }
41else if (type == typeof(float))
42 {
43 obj = (BitConverter.ToSingle(data, 0));
44 }
45else if (type == typeof(double))
46 {
47 obj = (BitConverter.ToDouble(data, 0));
48 }
49else if (type == typeof(decimal))
50 {
51 obj = (BitConverter.ToDouble(data, 0));
52 }
53else if (type == typeof(DateTime))
54 {
55var dstr = Encoding.UTF8.GetString(data);
56var ticks = long.Parse(dstr.Substring(2));
57 obj = (new DateTime(ticks));
58 }
59else if (type.BaseType == typeof(Enum))
60 {
61var numType = Enum.GetUnderlyingType(type);
62
63if (numType == typeof(byte))
64 {
65 obj = Enum.ToObject(type, data[0]);
66 }
67else if (numType == typeof(short))
68 {
69 obj = Enum.ToObject(type, BitConverter.ToInt16(data, 0));
70 }
71else if (numType == typeof(int))
72 {
73 obj = Enum.ToObject(type, BitConverter.ToInt32(data, 0));
74 }
75else
76 {
77 obj = Enum.ToObject(type, BitConverter.ToInt64(data, 0));
78 }
79 }
80else if (type == typeof(byte[]))
81 {
82 obj = (byte[])data;
83 }
84else if (type.IsGenericType)
85 {
86if (TypeHelper.ListTypeStrs.Contains(type.Name))
87 {
88 obj = DeserializeList(type, data);
89 }
90else if (TypeHelper.DicTypeStrs.Contains(type.Name))
91 {
92 obj = DeserializeDic(type, data);
93 }
94else
95 {
96 obj = DeserializeClass(type, data);
97 }
98 }
99else if (type.IsClass)
100 {
101 obj = DeserializeClass(type, data);
102 }
103else if (type.IsArray)
104 {
105 obj = DeserializeArray(type, data);
106 }
107else
108 {
109throw new RPCPamarsException("ParamsSerializeUtil.Deserialize 未定义的类型:" + type.ToString()); 110 }
111
112 }
113return obj;
114 }
View Code
其他详细的代码可以查看
功能基本实现了,下⾯对⽐⼀下10000次的实体序列化与反序列化测试结果:
实体代码:
1var groupInfo = new GroupInfo()
2 {
3 GroupID = 1,
4 IsTemporary = false,
5 Name = "yswenli group",
6 Created = DateTimeHelper.Now,
7 Creator = new UserInfo()
8 {
9
10 ID = 1,
11 Birthday = DateTimeHelper.Now.AddYears(-100),
12 UserName = "yswenli"
13 },
14 Users = new System.Collections.Generic.List<UserInfo>()
15 {
16new UserInfo()
17 {
18
19 ID = 1,
20 Birthday = DateTimeHelper.Now.AddYears(-100),
21 UserName = "yswenli"
22 }
23 }
24 };
测试代码:
1public static byte[] SerializeBinary(object request)
2 {
3
4 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer =
5
6new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
7
8using (System.IO.MemoryStream memStream = new System.IO.MemoryStream())
9 {
10 serializer.Serialize(memStream, request);
11
12return memStream.ToArray();
13 }
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论