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小时内删除。