细说C#中的序列化与反序列化的基本原理和过程
虽然我们平时都使用第三方库来进行序列化和反序列化,用起来也很方便,但至少得明白序列化与反序列化的基本原理。
懂得人就别看了!
注意:从.NET Framework 2.0 开始,序列化格式化器类SoapFormatter已过时。请改用 BinaryFormatter。
- 序列化:把目标对象转换为字节流的过程
- 反序列化:把字节流转换回对象的过程
序列化与反序列化需要一个序列化器类:即System.Runtime.Serialization.Formatters.Binary.BinaryFormatter类
实例化一个格式化器BinaryFormatter类:BinaryFormatter binaryFormatter = new BinaryFormatter();
一、序列化:
binaryFormatter.Serialize(Stream stream, Object obj);
- 该方法把一个或多个目标对象序列化为字节流并保存到目标流对象stream中。需要提供一个目标流对象stream(stream对象可以是基类Stream的派生类:
FileStream、MemoryStream、NetWorkStream等流对象);
序列化过程:
- 序列化时,首先判断每个对象的类型定义是否应用了可序列化
[Serializable]特性,否则抛出异常。 - 其次调用对象中那些被标记了
[OnSerializing]特性的所有方法。(即:执行序列化前,先调用该方法做一些事情) - 接下来,利用反射机制来取得每个目标对象的类型中所有需要序列化的实例字段的信息,并读取对应字段的值保存到字节流中。
- 序列化时,还保存了目标类型的全名、定义类型程序集的全名,作为标识信息保存到流中(用于反序列化)。
- 最后,调用所有被标记了
[OnSerialized]特性的方法。(即:序列化完成后,调用该方法做一些事情)
二、反序列化:
SomeObject obj = (SomeObject)binaryFormatter.Deserialize(Stream stream);
- 该方法把目标流对象stream中的字节流反序列化为Object对象,可根据需求进行转型为对应的目标对象
反序列化过程:
- 反序列化时,首先从字节流中读取程序集的标识信息,然后调用
System.Reflection.Assembly类的Load()方法加载该程序集到当前的AppDomain中,只有当程序集加载成功后,格式化器才能在程序集中查找是否存在与需要被反序列化的对象的类型信息相同的类型 - 找到类型后,调用对象中那些被标记了
[OnDeserializing]特性的所有方法 - 接下来利用该类型创建实例
- 然后从字节流中获取对应字段的值对该实例进行初始化。
- 最后,调用所有被标记了
[OnDeserialized]特性的方法。
此过程中若找不到匹配的类型,则会抛出异常终止反序列化。但是,我在利用第三方类库反序列化JSON文件时,JSON文件并不存在对象名和程序集名的标识信息,第三方类库的格式化器应该是根据各个对象的成员名称、类型,在当前AppDomain中的所有程序集中进行查找匹配的类型。
注意:
- 最好把序列化或反序列化的过程放进try块中,用catch (SerializationException e)块处理需要处理的异常,并在finally块中释放资源(关闭流)。
- 可以把流的定义放在using语句的“()”中,把序列化反序列化代码放在using块内,来达到自动释放资源的目的。
三、序列化配置
在执行序列化和反序列化之前,可以对格式化器的Context属性进行设置,Context属性是一个StreamingContext结构
binaryFormatter.Context = new StreamingContext(StreamingContextStates.Remoting);//指定为来源和目的地是远程的
StreamingContext结构的属性有两个:
State属性,是一个枚举类型StreamingContextStates的值,用来说明序列化和反序列化的对象的来源和目的地Context属性,一个上下文对象的引用,包含了用户希望得到的任何上下文信息
StreamingContext结构存在的意义就是通过State属性的值描述给定的序列化流的源和目标,并利用Context属性提供一个由调用方定义的附加上下文。
(因为同一个被序列化好的对象可能会有不同的目的地,如不同机器,不同进程中等,我们就可以通过State属性的状态来标识对象的目的地)
示例:利用序列化和反序列化,定义一个深度克隆一个对象的方法
public object DeepCloneObject(object oldObj)
{
try
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Context = new StreamingContext(StreamingContextStates.Clone);
//把对象序列化到流中
bf.Serialize(stream, oldObj);
//在进行反序列化前,需要先定位到内存流的起始位置
stream.Position = 0;
//将内存流中的内容反序列化成新的对象
return bf.Deserialize(stream);
}
}
catch(SerializationException e)
{
Console.WriteLine("序列化和反序列化时出错了,错误信息为:" + e.Message);
//不做处理,重新抛出原异常对象
throw;
}
finally
{
//using中的stream对象会被自动释放,这里不要对它处理
}
}
四、如果有些类型的成员无法进行序列化或反序列化,则可以为该类型实现接口ISerializationCallbackReceiver,该接口定义了两个方法:
比如在Unity3d中,无法序列化枚举类型的成员,就需要把他标记为[NonSerialized]不对他处理,然后定义一个该成员的字符串形式的成员,通过该字符串和对应枚举类型的转换,就可以达到序列化的目的了。如下代码:
public enum ItemType
{
left,
right
}
public class ScoreModel:ISerializationCallbackReceiver
{
public int Score { get; set; }
[NonSerialized]
public ItemType itemType;
public string itemTypeString;
//反序列化完成自动后调用
public void OnAfterDeserialize()
{
itemType = (ItemType)Enum.Parse(typeof(ItemType), itemTypeString);
}
//进行序列化之前自动调用
public void OnBeforeSerialize()
{
itemTypeString = itemType.ToString();
}
}
五、关于序列化为派生类类型的情况
即使是第三方类库,可能也无法处理这种情况,比如:从JSON中反序列化后得到的对象的成员是一个基类类型的,如果直接把该成员强转为我们实际需要的子类类型,正常情况下是不行的,这时就需要自定义一些方法来实现了,利用协变在序列化过程中返回子类类型的对象给基类类型,这样得到的基类类型就可以强转为子类类型了。具体实现代码,大家可以搜起来!
细说C#中的序列化与反序列化的基本原理和过程的更多相关文章
- Net中JSON序列化和反序列化处理(日期时间特殊处理)
0 缘由 笔者最近在web api端使用Json.Net进行序列化处理,而在调用端使用DataContractSerializer进行反序列化,遇到日期时间处理反序列化不成功[备注:笔者使用Net ...
- day5-python中的序列化与反序列化-json&pickle
一.概述 玩过稍微大型一点的游戏的朋友都知道,很多游戏的存档功能使得我们可以方便地迅速进入上一次退出的状态(包括装备.等级.经验值等在内的一切运行时数据),那么在程序开发中也存在这样的需求:比较简单的 ...
- 在net中json序列化与反序列化 面向对象六大原则 (第一篇) 一步一步带你了解linq to Object 10分钟浅谈泛型协变与逆变
在net中json序列化与反序列化 准备好饮料,我们一起来玩玩JSON,什么是Json:一种数据表示形式,JSON:JavaScript Object Notation对象表示法 Json语法规则 ...
- 浅谈C#中的序列化与反序列化
今天我利用这篇文章给大家讲解一下C#中的序列化与反序列化.这两个概念我们再开发中经常用到,但是我们绝大部分只用到了其中的一部分,剩下的部分很多开发人员并不清楚,甚至可以说是不知道.因此我希望通过这篇文 ...
- javaIO中的序列化和反序列化
javaIO中的序列化和反序列化 1.什么是序列化?它是来解决什么问题的 1.我们创建的对象,一般情况下在内存中,程序关闭,或者因为没有地址指向而导致垃圾回收 2.这样,我们的对象就会丢失 3.那么我 ...
- C#中JSON序列化和反序列化
有一段时间没有到博客园写技术博客了,不过每天逛逛博客园中大牛的博客还是有的,学无止境…… 最近在写些调用他人接口的程序,用到了大量的JSON.XML序列化和反序列化,今天就来总结下json的序列化和反 ...
- C#中的 序列化和反序列化
什么是序列化和反序列化? 序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用. 我想最主要的作用有: 1.在进程下次启动时读取上次保存的对象的 ...
- C#中的序列化与反序列化
眼看XX鸟的课程关于C#的知识点就要学完了,翻看网络中流传的教程还是发现了一个课程中没有讲到的知识点:序列化与反序列化 无奈还是了解一下并操作一番,以备后用吧 介绍:就是将对象信息转化为二进制信息以便 ...
- K:java中的序列化与反序列化
Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?以下内容将围绕这些问题进行展开讨论. Java序列化与反序列化 简单来说Java序列化是指把Java对象转 ...
随机推荐
- asp.net站点阻止某个文件夹或者文件被浏览器访问
一个站点根目录下面有一个Config文件夹,这个文件夹里面都是一些json格式的txt文本,文本是一种静态资源,如果知道这个文本的地址,就可以在浏览器中输入地址打开这个文本,别人就可以看到站点的配置, ...
- linux 建议锁和强制锁
作为APUE 14.3节的参考 linux是有强制锁的,但是默认不开启.想让linux支持强制性锁,不但在mount的时候需要加上-o mand,而且对要加锁的文件也需要设置相关权限. . ...
- JVM锁实现探究2:synchronized深探
本文来自网易云社区 作者:马进 这里我们来聊聊synchronized,以及wait(),notify()的实现原理. 在深入介绍synchronized原理之前,先介绍两种不同的锁实现. 一.阻塞锁 ...
- spring @Async 线程池使用
最近公司项目正逐渐从dubbo向springCloud转型,在本次新开发的需求中,全部使用springcloud进行,在使用时线程池,考虑使用spring封装的线程池,现将本次使用心得及内容记录下来 ...
- hive的安装与配置 mysql安装 启动
三种模式 内嵌模式:元数据保持在内嵌的derby模式,只允许一个会话连接 本地独立模式:在本地安装Mysql,吧元数据放到mySql内 远程模式:元数据放置在远程的Mysql数据库 1.下载Hive安 ...
- Django REST framework序列化
一.简介 Django REST framework是基于Django实现的一个RESTful风格API框架,能够帮助我们快速开发RESTful风格的API. 官网:https://www.djang ...
- [Swift实际操作]九、完整实例-(3)创建和安装开发证书、发布证书及开发证书配置文件、发布证书配置文件
本文将为你演示,如何创建开发证书和发布证书,以及其他辅助内容.首先打开浏览器,进入[苹果开发者网站]输入[Apple ID]和[密码],点击登录按钮,进入开发者管理后台. 点击左侧的[Membersh ...
- CF138D World of Darkraft
$ \color{#0066ff}{ 题目描述 }$ n*m的格子,每个格子有字符'L','R',X',初始可以选择所有格子. 当选了 'L'的格子时,当前格子左下右上这条线上所有点不能选; 当选了 ...
- Xilinx FPGA使用——ROM初始化文件
在调用ROM的IP Core时,需要对其进行初始化,利用MATLAB生成其初始化数据文件. 工具:ISE 14.7.MATLAB.notepad++ 废话不多说,直接上MATLAB代码,生成了一个10 ...
- python学习之路---day02
一:while循环 while 条件语句 #如果条件成立则执行下面的循环语句 循环语句 eg1:1+2+3+4+5......+100=? num=0 #给num和sum赋初值 sum=0 while ...