二进制序列化可以方便快捷的将对象进行持久化或者网络传输,并且体积小、性能高,应用面甚至还要高于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、反射等来实现序列化与反序列化;

序列化实现如下:

  1         public static byte[] Serialize(object param)
  2         {
  3             List<byte> datas = new List<byte>();
  4
  5             var len = 0;
  6
  7             byte[] data = null;
  8
  9             if (param == null)
 10             {
 11                 len = 0;
 12             }
 13             else
 14             {
 15                 if (param is string)
 16                 {
 17                     data = Encoding.UTF8.GetBytes((string)param);
 18                 }
 19                 else if (param is byte)
 20                 {
 21                     data = new byte[] { (byte)param };
 22                 }
 23                 else if (param is bool)
 24                 {
 25                     data = BitConverter.GetBytes((bool)param);
 26                 }
 27                 else if (param is short)
 28                 {
 29                     data = BitConverter.GetBytes((short)param);
 30                 }
 31                 else if (param is int)
 32                 {
 33                     data = BitConverter.GetBytes((int)param);
 34                 }
 35                 else if (param is long)
 36                 {
 37                     data = BitConverter.GetBytes((long)param);
 38                 }
 39                 else if (param is float)
 40                 {
 41                     data = BitConverter.GetBytes((float)param);
 42                 }
 43                 else if (param is double)
 44                 {
 45                     data = BitConverter.GetBytes((double)param);
 46                 }
 47                 else if (param is DateTime)
 48                 {
 49                     var str = "wl" + ((DateTime)param).Ticks;
 50                     data = Encoding.UTF8.GetBytes(str);
 51                 }
 52                 else if (param is Enum)
 53                 {
 54                     var enumValType = Enum.GetUnderlyingType(param.GetType());
 55
 56                     if (enumValType == typeof(byte))
 57                     {
 58                         data = new byte[] { (byte)param };
 59                     }
 60                     else if (enumValType == typeof(short))
 61                     {
 62                         data = BitConverter.GetBytes((Int16)param);
 63                     }
 64                     else if (enumValType == typeof(int))
 65                     {
 66                         data = BitConverter.GetBytes((Int32)param);
 67                     }
 68                     else
 69                     {
 70                         data = BitConverter.GetBytes((Int64)param);
 71                     }
 72                 }
 73                 else if (param is byte[])
 74                 {
 75                     data = (byte[])param;
 76                 }
 77                 else
 78                 {
 79                     var type = param.GetType();
 80
 81
 82                     if (type.IsGenericType || type.IsArray)
 83                     {
 84                         if (TypeHelper.DicTypeStrs.Contains(type.Name))
 85                             data = SerializeDic((System.Collections.IDictionary)param);
 86                         else if (TypeHelper.ListTypeStrs.Contains(type.Name) || type.IsArray)
 87                             data = SerializeList((System.Collections.IEnumerable)param);
 88                         else
 89                             data = SerializeClass(param, type);
 90                     }
 91                     else if (type.IsClass)
 92                     {
 93                         data = SerializeClass(param, type);
 94                     }
 95
 96                 }
 97                 if (data != null)
 98                     len = data.Length;
 99             }
100             datas.AddRange(BitConverter.GetBytes(len));
101             if (len > 0)
102             {
103                 datas.AddRange(data);
104             }
105             return datas.Count == 0 ? null : datas.ToArray();
106         }

反序列化实现如下:

  1         public static object Deserialize(Type type, byte[] datas, ref int offset)
  2         {
  3             dynamic obj = null;
  4
  5             var len = 0;
  6
  7             byte[] data = null;
  8
  9             len = BitConverter.ToInt32(datas, offset);
 10             offset += 4;
 11             if (len > 0)
 12             {
 13                 data = new byte[len];
 14                 Buffer.BlockCopy(datas, offset, data, 0, len);
 15                 offset += len;
 16
 17                 if (type == typeof(string))
 18                 {
 19                     obj = Encoding.UTF8.GetString(data);
 20                 }
 21                 else if (type == typeof(byte))
 22                 {
 23                     obj = (data);
 24                 }
 25                 else if (type == typeof(bool))
 26                 {
 27                     obj = (BitConverter.ToBoolean(data, 0));
 28                 }
 29                 else if (type == typeof(short))
 30                 {
 31                     obj = (BitConverter.ToInt16(data, 0));
 32                 }
 33                 else if (type == typeof(int))
 34                 {
 35                     obj = (BitConverter.ToInt32(data, 0));
 36                 }
 37                 else if (type == typeof(long))
 38                 {
 39                     obj = (BitConverter.ToInt64(data, 0));
 40                 }
 41                 else if (type == typeof(float))
 42                 {
 43                     obj = (BitConverter.ToSingle(data, 0));
 44                 }
 45                 else if (type == typeof(double))
 46                 {
 47                     obj = (BitConverter.ToDouble(data, 0));
 48                 }
 49                 else if (type == typeof(decimal))
 50                 {
 51                     obj = (BitConverter.ToDouble(data, 0));
 52                 }
 53                 else if (type == typeof(DateTime))
 54                 {
 55                     var dstr = Encoding.UTF8.GetString(data);
 56                     var ticks = long.Parse(dstr.Substring(2));
 57                     obj = (new DateTime(ticks));
 58                 }
 59                 else if (type.BaseType == typeof(Enum))
 60                 {
 61                     var numType = Enum.GetUnderlyingType(type);
 62
 63                     if (numType == typeof(byte))
 64                     {
 65                         obj = Enum.ToObject(type, data[0]);
 66                     }
 67                     else if (numType == typeof(short))
 68                     {
 69                         obj = Enum.ToObject(type, BitConverter.ToInt16(data, 0));
 70                     }
 71                     else if (numType == typeof(int))
 72                     {
 73                         obj = Enum.ToObject(type, BitConverter.ToInt32(data, 0));
 74                     }
 75                     else
 76                     {
 77                         obj = Enum.ToObject(type, BitConverter.ToInt64(data, 0));
 78                     }
 79                 }
 80                 else if (type == typeof(byte[]))
 81                 {
 82                     obj = (byte[])data;
 83                 }
 84                 else if (type.IsGenericType)
 85                 {
 86                     if (TypeHelper.ListTypeStrs.Contains(type.Name))
 87                     {
 88                         obj = DeserializeList(type, data);
 89                     }
 90                     else if (TypeHelper.DicTypeStrs.Contains(type.Name))
 91                     {
 92                         obj = DeserializeDic(type, data);
 93                     }
 94                     else
 95                     {
 96                         obj = DeserializeClass(type, data);
 97                     }
 98                 }
 99                 else if (type.IsClass)
100                 {
101                     obj = DeserializeClass(type, data);
102                 }
103                 else if (type.IsArray)
104                 {
105                     obj = DeserializeArray(type, data);
106                 }
107                 else
108                 {
109                     throw new RPCPamarsException("ParamsSerializeUtil.Deserialize 未定义的类型:" + type.ToString());
110                 }
111
112             }
113             return obj;
114         }

其他详细的代码可以查看ParamsSerializeUtil.cs

功能基本实现了,下面对比一下10000次的实体序列化与反序列化测试结果:

实体代码:

 1             var 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                 {
16                     new UserInfo()
17                     {
18
19                         ID = 1,
20                         Birthday = DateTimeHelper.Now.AddYears(-100),
21                         UserName = "yswenli"
22                     }
23                 }
24             };

测试代码:

 1         public static byte[] SerializeBinary(object request)
 2         {
 3
 4             System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer =
 5
 6             new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
 7
 8             using (System.IO.MemoryStream memStream = new System.IO.MemoryStream())
 9             {
10                 serializer.Serialize(memStream, request);
11
12                 return memStream.ToArray();
13             }
14         }
15
16
17         public static object DeSerializeBinary(byte[] data)
18         {
19             using (System.IO.MemoryStream memStream = new System.IO.MemoryStream(data))
20             {
21                 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter deserializer =
22
23                 new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
24
25                 return deserializer.Deserialize(memStream);
26             }
27         }
28
29         static void SerializeTest()
30         {
31             var groupInfo = new GroupInfo()
32             {
33                 GroupID = 1,
34                 IsTemporary = false,
35                 Name = "yswenli group",
36                 Created = DateTimeHelper.Now,
37                 Creator = new UserInfo()
38                 {
39
40                     ID = 1,
41                     Birthday = DateTimeHelper.Now.AddYears(-100),
42                     UserName = "yswenli"
43                 },
44                 Users = new System.Collections.Generic.List<UserInfo>()
45                 {
46                     new UserInfo()
47                     {
48
49                         ID = 1,
50                         Birthday = DateTimeHelper.Now.AddYears(-100),
51                         UserName = "yswenli"
52                     }
53                 }
54             };
55
56             var count = 100000;
57             var len1 = 0;
58             var len2 = 0;
59
60             Stopwatch sw = new Stopwatch();
61             sw.Start();
62
63             List<byte[]> list = new List<byte[]>();
64             for (int i = 0; i < count; i++)
65             {
66                 var bytes = SerializeBinary(groupInfo);
67                 len1 = bytes.Length;
68                 list.Add(bytes);
69             }
70             ConsoleHelper.WriteLine($"BinaryFormatter实体序列化平均:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
71
72             sw.Restart();
73             for (int i = 0; i < count; i++)
74             {
75                 var obj = DeSerializeBinary(list[i]);
76             }
77             ConsoleHelper.WriteLine($"BinaryFormatter实体反序列化平均:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
78             ConsoleHelper.WriteLine($"BinaryFormatter序列化生成bytes大小:{len1 * count * 1.0 / 1024 / 1024} Mb");
79             list.Clear();
80             sw.Restart();
81
82             for (int i = 0; i < count; i++)
83             {
84                 var bytes = RPC.Serialize.ParamsSerializeUtil.Serialize(groupInfo);
85                 len2 = bytes.Length;
86                 list.Add(bytes);
87             }
88             ConsoleHelper.WriteLine($"ParamsSerializeUtil实体序列化平均:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
89             sw.Restart();
90             for (int i = 0; i < count; i++)
91             {
92                 int os = 0;
93
94                 var obj = RPC.Serialize.ParamsSerializeUtil.Deserialize(groupInfo.GetType(), list[i], ref os);
95             }
96             ConsoleHelper.WriteLine($"ParamsSerializeUtil实体反序列化平均:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
97             ConsoleHelper.WriteLine($"ParamsSerializeUtil序列化生成bytes大小:{len2 * count * 1.0 / 1024 / 1024} Mb");
98             sw.Stop();
99         }

运行结果:

感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是yswenli 。

自行实现比dotcore/dotnet更方便更高性能的对象二进制序列化相关推荐

  1. C# dotnet 一个看上去还能用的二进制序列化帮助类

    这仅是一个辅助方法帮助类,可以协助小伙伴写二进制序列化的效率,代码也还看的过去 在开始之前,我需要说明的是,如果不是必要,不要使用二进制序列化.因为很难做到版本兼容,如果写错了也不知道是哪里写错了,调 ...

  2. msdn安装后怎么用_Win10不好用?安装官方版精简Win10后,运行比win7更快更流畅

    尽管不想承认,确实是大白菜的电脑配置有点旧了,导致从win7升级最新版win10系统后,电脑是100个不好用!!! 虽然,非常怀念使用win7系统时,那种操作的流畅度,那种运行的速度~ 但是,大白菜和 ...

  3. 安装更强大更美观的zsh,配置oh my zsh及插件

    安装更强大更美观的zsh,配置oh my zsh及插件 #0x0 安装zsh #0x1 安装oh my zsh #0x2 配置zshrc #0x3 配置主题 #0x4 安装插件 #0x5 小结 #0x ...

  4. 使用现场总线更快更远

    使用现场总线更快更远 Going faster and further with Fieldbus PROCENTEC等行业专家表示,基于RS-485的现场总线技术(PROFIBUS®)和工业以太网( ...

  5. Google 开源的依赖注入库,比 Spring 更小更快!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:GinoBeFunny zhuanlan.zhihu.com ...

  6. 苹果公司提出Mobile-ViT | 更小更轻精度更高,MobileNets或成为历史

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者丨ChaucerG 来源丨集智书童 MobileviT是一个用于移动设备的轻量级通用可视化Tran ...

  7. 更快更强,谷歌提出SWideRNet:全景分割新标杆来啦!

    作者丨Happy 编辑丨极市平台 导读 本文是DeepLab系列作者"Liang-Chieh Chen"大神在全景分割领域的又一力作.它在Wide-ResNet的基础上引入SE与& ...

  8. 如何更好的创建Java对象

    2019独角兽企业重金招聘Python工程师标准>>> 静态工厂 除了使用构造函数创建对象外,还可以使用静态工厂来创建对象,JDK中大量使用了这种技巧,例如: public stat ...

  9. 科宇扫地机器人_我的三年16台智能扫地机器人使用回忆录 篇四:扫地谁更精准更干净?新一代3D视讯+激光成像 PK 老式激光扫描,万字实测对比分享...

    我的三年16台智能扫地机器人使用回忆录 篇四:扫地谁更精准更干净?新一代3D视讯+激光成像 PK 老式激光扫描,万字实测对比分享 2019-05-23 11:22:00 37点赞 166收藏 53评论 ...

最新文章

  1. 俄通信监管机构回应封锁微信: 收到资料核验后将解除封锁
  2. 示波器上mode选择开关上的norm和auto是什么意思?
  3. python为什么中文要encoding-python 中文编码问题如何解决?
  4. 1.5 matlab常量与变量
  5. 【Linux】20.shell脚本 检测是否 ping 通
  6. leetcode 258. 各位相加(Java版)
  7. linux lsof/netstat查看进程和端口号相关命令:
  8. linux 命令api,linux命令行下字典,使用有道API
  9. tar.gz及tar.bz2两种常见格式的打包压缩及解压方法
  10. java 多个timer_java – Timer正在创建多个计时器实例
  11. [转]win7-64位系统添加access的ODBC数据源 看不到其它数据源的问题
  12. 【C++】【GADL】读取栅格数据获取信息
  13. jupyter notebook 快捷键
  14. 曼联队选择Tezos作为官方区块链和训练工具包合作伙伴
  15. 计算机更新后无法远程,重装系统后无法进行远程桌面连接怎么办
  16. 集成第三方单点登录JIRA(Colfluence同理)
  17. Python基础——PyCharm版本——第八章、文件I/O(核心2——JSON序列化与反序列化——超重点)
  18. HDU1849 SG函数
  19. 蚂蚁金服Java后端(一面)面试题
  20. 疲劳载荷与S-N曲线

热门文章

  1. bat脚本案例:实现炫酷的文字logo
  2. 【JavaSe,Day03,note】
  3. Flutter的android项目跳转谷歌市场
  4. 【CTF特训营】 Reverse篇 2.Reverse分析
  5. 分享35款非常有用的免费字体
  6. php+qq音乐api接口,QQ音乐API | 小灰灰博客
  7. 对mtk平台的一些认识
  8. ubuntu安装CD-HIT
  9. 电磁场与电磁波(10)——电容与部分电容
  10. 基于python-opencv实现鼠标绘制矩形、直线并根据直线斜率实现图片旋转