.Net中的序列化和反序列化详解
序列化通俗地讲就是将一个对象转换成一个字节流的过程,这样就可以轻松保存在磁盘文件或数据库中。反序列化是序列化的逆过程,就是将一个字节流转换回原来的对象的过程。
然而为什么需要序列化和反序列化这样的机制呢?这个问题也就涉及到序列化和反序列化的用途了,
对于序列化的主要用途有:
1)、将应用程序的状态保存在一个磁盘文件或数据库中,并在应用程序下次运行时恢复状态。例如, Asp.net 中利用序列化和反2)、序列化来保存和恢复会话状态。
3)、一组对象可以轻松复制到Windows 窗体的剪贴板中,再粘贴回同一个或者另一个应用程序。
将对象按值从一个应用程序域中发送到另一个程序域
并且如果把对象序列化成内存中的字节流,就可以利用一些其他的技术来处理数据,例如,对数据进行加密和压缩等。
序列化和反序列化的简单使用:
using System;using System.IO;using System.Runtime.Serialization.Formatters.Binary;namespace Serializable{ [Serializable] public class Person { public string personName; [NonSerialized] public string personHeight; private int personAge; public int PersonAge { get { return personAge; } set { personAge = value; } } public void Write() { Console.WriteLine("Person Name: "+personName); Console.WriteLine("Person Height: " +personHeight); Console.WriteLine("Person Age: "+ personAge); } } class Program { static void Main(string[] args) { Person person = new Person(); person.personName = "Jerry"; person.personHeight = "175CM"; person.PersonAge = 22; Stream stream = Serialize(person); //为了演示,都重置 stream.Position = 0; person = null; person = Deserialize(stream); person.Write(); Console.Read(); } private static MemoryStream Serialize(Person person) { MemoryStream stream = new MemoryStream(); // 构造二进制序列化格式器 BinaryFormatter binaryFormatter = new BinaryFormatter(); // 告诉序列化器将对象序列化到一个流中 binaryFormatter.Serialize(stream, person); return stream; } private static Person Deserialize(Stream stream) { BinaryFormatter binaryFormatter = new BinaryFormatter(); return (Person)binaryFormatter.Deserialize(stream); } }}从中可以看出除了标记NonSerialized的其他成员都能序列化,注意这个属性只能应用于一个类型中的字段,而且会被派生类型继承。
SOAP 和XML 的序列化和反序列化和上面类似,只需要改下格式化器就可以了, 这里我就不列出来了。
三、控制序列化和反序列化
有两种方式来实现控制序列化和反序列化:
通过OnSerializing, OnSerialized,OnDeserializing, OnDeserialized,NonSerialized和OptionalField等属性
实现System.Runtime.Serialization.ISerializable接口
第一种方式实现控制序列化和反序列化代码:
using System;using System.IO;using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;namespace ControlSerialization{ [Serializable] public class Circle { private double radius; //半径 [NonSerialized] public double area; //面积 public Circle(double inputradiu) { radius = inputradiu; area = Math.PI * radius * radius; } [OnDeserialized] private void OnDeserialized(StreamingContext context) { area = Math.PI * radius * radius; } public void Write() { Console.WriteLine("Radius is: " + radius); Console.WriteLine("Area is: " + area); } } class Program { static void Main(string[] args) { Circle c = new Circle(10); MemoryStream stream =new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); // 将对象序列化到内存流中,这里可以使用System.IO.Stream抽象类中派生的任何类型的一个对象, 这里我使用了 MemoryStream类型。 formatter.Serialize(stream,c); stream.Position = 0; c = null; c = (Circle)formatter.Deserialize(stream); c.Write(); Console.Read(); } }}注意:如果注释掉 OnDeserialized属性的话,area字段的值就是0了,因为area字段没有被序列化到流中。
在上面需要序列化的对象中,格式化器只会序列化对象的radius字段的值。area字段中的值不会序列化,因为该字段已经应用了NonSerializedAttribute属性,然后我们用Circle c=new Circle(10)这样代码构建一个Circle对象时,在内部,area会设置一个约为314.159这样的值,这个对象序列化时,只有radius的字段的值(10)写入流中, 但当反序列化成一个Circle对象时,它的area字段的值会初始化为0,而不是约314.159的一个值。为了解决这样的问题,所以自定义一个方法应用OnDeserializedAttribute属性。此时的执行过程为:每次反序列化类型的一个实例,格式化器都会检查类型中是否定义了 一个应用了该attribute的方法,如果是,就调用该方法,调用该方法时,所有可序列化的字段都会被正确设置。除了OnDeserializedAttribute这个定制attribute,system.Runtime.Serialization命名空间还定义了OnSerializingAttribute,OnSerializedAttribute和OnDeserializingAttribute这些定制属性。
实现ISerializable接口方式控制序列化和反序列化代码:
using System;using System.IO;using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;using System.Security.Permissions;namespace ControlSerilization2{ [Serializable] public class MyObject : ISerializable { public int n1; public intn2; [NonSerialized] public String str; public MyObject() { } protected MyObject(SerializationInfo info, StreamingContext context) { n1 = info.GetInt32("i"); n2 = info.GetInt32("j"); str = info.GetString("k"); } [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("i", n1); info.AddValue("j", n2); info.AddValue("k", str); } public void Write() { Console.WriteLine("n1 is: " + n1); Console.WriteLine("n2 is: " + n2); Console.WriteLine("str is: " + str); } } class Program { static void Main(string[] args) { MyObject obj = new MyObject(); obj.n1 = 2; obj.n2 = 3; obj.str = "Jeffy"; MemoryStream stream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); // 将对象序列化到内存流中,这里可以使用System.IO.Stream抽象类中派生的任何类型的一个对象, 这里我使用了 MemoryStream类型。 formatter.Serialize(stream, obj); stream.Position = 0; obj = null; obj = (MyObject)formatter.Deserialize(stream); obj.Write(); Console.Read(); } }}四、格式化器如何序列化和反序列化
从上面的分析中可以看出,进行序列化和反序列化主要是格式化器在工作的,然而下面就是要讲讲格式化器是如何序列化一个应用了 SerializableAttribute 属性的对象。
1、格式化器调用FormatterServices的GetSerializableMembers方法:public static MemberInfo[] GetSerializableMembers(Type type,StreamingContext context);这个方法利用发射获取类型的public和private实现字段(标记了NonSerializedAttributee属性的字段除外)。方法返回由MemberInfo对象构成的一个数组,其中每个元素对应于一个可序列化的实例字段。
2、对象被序列化,System.Reflection.MemberInfo对象数组传给FormatterServices的静态方法GetObjectData: public static object[] GetObjectData(Object obj,MemberInfo[] members); 这个方法返回一个Object数组,其中每个元素都标识了被序列化的那个对象中的一个字段的值。
3、格式化器将程序集标识和类型的完整名称写入流中。
4、格式化器然后遍历两个数组中的元素,将每个成员的名称和值写入流中。
接下来是解释格式化器如何自动反序列化一个应用了 SerializableAttribute属性的对象。
1、格式化器从流中读取程序集标识和完整类型名称。
2、格式化器调用FormatterServices的静态方法GetUninitializedObject: public static Object GetUninitializedObject(Type ttype);这个方法为一个新对象分配内存,但不为对象调用构造器。然而,对象的所有字段都被初始化为0或null.
3格式化器现在构造并初始化一个MemberInfo数组,调用FormatterServices的GetSerializableMembers方法,这个方法返回序列化好、现在需要反序列化的一组字段。
4、格式化器根据流中包含的数据创建并初始化一个Object数组。
5、将对新分配的对象、MemberInfo数组以及并行Object数组的引用传给FormatterServices的静态方法PopulateObjectMembers:
public static Object PopulateObjectMembers(Object obj,MemberInfo[] members,Object[] data);这个方法遍历数组,将每个字段初始化成对应的值。
注:格式化如何序列化和反序列对象部分摘自CLR via C#(第三版),写在这里可以让初学者进一步理解格式化器在序列化和反序列化过程中所做的工作。
写到这里这篇关于序列化和反序列的文章终于结束了, 希望对朋友有帮助。
.Net中的序列化和反序列化详解的更多相关文章
- Java中的序列化Serialable高级详解
来自[http://blog.csdn.net/jiangwei0910410003/article/details/18989711] 引言 将 Java 对象序列化为二进制文件的 Java 序列化 ...
- go语言之行--文件操作、命令行参数、序列化与反序列化详解
一.简介 文件操作对于我们来说也是非常常用的,在python中使用open函数来对文件进行操作,而在go语言中我们使用os.File对文件进行操作. 二.终端读写 操作终端句柄常量 os.Stdin: ...
- C# 序列化和反序列化 详解
什么是序列化以及如何实现序列化? 如何将对象数据写入 XML 文件? 如何从 XML 文件读取对象数据? 什么是序列化以及如何实现序列化? 序列化是通过将对象转换为字节流,从而存储对象或将对象传输到内 ...
- 《Java基础知识》序列化与反序列化详解
序列化的作用:为了不同jvm之间共享实例对象的一种解决方案.由java提供此机制. 序列化应用场景: 1. 分布式传递对象. 2. 网络传递对象. 3. tomcat关闭以后会把session对象序列 ...
- 前端后台以及游戏中使用Google Protocol Buffer详解
前端后台以及游戏中使用Google Protocol Buffer详解 0.什么是protoBuf protoBuf是一种灵活高效的独立于语言平台的结构化数据表示方法,与XML相比,protoBuf更 ...
- PHP 中 16 个魔术方法详解
PHP 中 16 个魔术方法详解 前言 PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用. 魔术方法包括: __constru ...
- php中的PDO函数库详解
PHP中的PDO函数库详解 PDO是一个“数据库访问抽象层”,作用是统一各种数据库的访问接口,与mysql和mysqli的函数库相比,PDO让跨数据库的使用更具有亲和力:与ADODB和MDB2相比,P ...
- [ 转载 ] Java开发中的23种设计模式详解(转)
Java开发中的23种设计模式详解(转) 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...
- php中流行的rpc框架详解
什么是RPC框架? 如果用一句话概括RPC就是:远程调用框架(Remote Procedure Call) 那什么是远程调用? 我的官方群点击此处. 通常我们调用一个php中的方法,比如这样一个函数方 ...
随机推荐
- 理解HTTP幂等性,分布式事物
理解HTTP幂等性 基于HTTP协议的Web API是时下最为流行的一种分布式服务提供方式.无论是在大型互联网应用还是企业级架构中,我们都见到了越来越多的SOA或RESTful的Web API.为什么 ...
- ajax 兼容性问题解决 集锦
这两天刚解决了ajax多浏览器兼容的问题,主要就针对Firefox的,开始还以为Firefox不支持ajax呢(别笑我呀,不怎么了解Firefox也没用过,呵呵),多亏看了下面的文章才让我了解ajax ...
- ny71 独木舟的旅行
独木舟上的旅行时间限制:3000 ms | 内存限制:65535 KB难度:2描述进行一次独木舟的旅行活动,独木舟可以在港口租到,并且之间没有区别.一条独木舟最多只能乘坐两个人,且乘客的总重量不能 ...
- ES6新特性概览1
本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用. ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony( ...
- gulp入门与一些基本设置
这里是gulp入门的一些操作,实现了编译sass文件.压缩.合并.添加版本号等基本功能. 友情提示,如果npm出现无法下载可以安装 cnpm.在安装完Nodejs 后 npm install cnpm ...
- HttpClient 教程 (一)
转自:http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2112804.html HttpClient 教程 (一) 前言 超文本传输协议 ...
- 将ASCII字符串转换为UNICODE字符串
写在前面的话:在MFC的网络编程中,由于现在项目都是使用UNICODE编码,但是网络API的许多函数却只能接受const char*的参数,所以经常会遇到需要将char*转换为TCHAR*的时候,有一 ...
- Win7网络修复,winsock/tcpip
1.win7自带网络诊断提示没有安装一个或多个协议,ip地址为169.254.x.x,dns地址为空 2.修复winsock时,提示系统找不到指定的文件. 解决办法: 1. netsh int ip ...
- div层上下左右居中
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- J2EE的13个规范总结
转载自:http://blog.csdn.net/zhuanzhe117/article/details/38763483 什么是J2EE? 在企业级应用中,都有一些通用企业需求模块,如数据库连接,邮 ...