第一节:序列化和反序列化快速入门

  static void Main(string[] args)
        {

            var objectGraph = new List<string> { "Jeff", "Kristin", "Aidan", "Grant" };

            Stream stream = SerializerToMemory(objectGraph);
            //为了演示,将一切都重置
            stream.Position = 0;
            objectGraph = null;

            objectGraph = (List<string>)DeserializerFromMemory(stream);
            foreach (var s in objectGraph)
            {
                Console.WriteLine(s);
            }}

private static MemoryStream SerializerToMemory(Object objectGraph)
{


//构造一个流来容纳序列化的对象
MemoryStream stream = new MemoryStream();
//构造一个序列化格式器,它负责所有的辛苦工作
BinaryFormatter formatter = new BinaryFormatter();
//告诉格式化器将对象序列化到流中
formatter.Serialize(stream, objectGraph);


return stream;
}
private static Object DeserializerFromMemory(Stream stream)
{
//构造一个序列化格式器来做所有辛苦工作
BinaryFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}

 

看起来一切都简单!SerializerToMemory方法构造一个MemoryStream对象。这个对象标明要将序列化好的对象放到哪里。然后,方法构造一个BinaryFormatter对象。格式化器是实现了System.Runtime.Serialization.IFormatter接口的一个类型,它知道如何序列化和反序列化一个对象图。FCL提供了两个格式化器:BinaryFormatter和System.Runtime.Serialization.Formatters.Soap.SoapFormatter(System.Runtime.Serialization.Formatters.Soap.dll程序集中实现的)。

注意  从.NET Framework3.5起,SoapFormatter类已被废弃,应避免在生产过程中使用。然而,对序列化代码进行调试时,它仍然有一定的用途,因为它能生成便于阅读的XML文本。要在生产过程中产用XML序列化和反序列化,请参见XmlSerializer 和DataContractSerializer类

要序列化一个对象图,只需要调用格式化器的Serialize方法,并向它传递两样东西:对一个流对象的引用,以及要序列化对象图的一个引用。流对象标识了序列化好的字节应放到哪里,它可以使从System.IO.Stream抽象类派生的任何一个对象。也就是说,可将对象图序列化成一个MemoryStream、FileStream或者NetworkStream等等。

Serialize的第二个参数是一个对象引用。这个对象可以使任何东西,可以使一个Int32,String,DateTime,Exception,List<String>或者Dictionary<Int32,DateTime>等等。

objectGraph参数引用的对象可饮用其他对象。例如,objectGraph可引用一个集合,而这个集合引用一个数组。这些对象还可以继承引用其他对象。当格式化器的Serialize方法被调用时,对象图中的所有对象都被序列化到流中。

格式化器参数对每个对象的类型进行描述的元数据,从而了解如何序列化完整的对象图。序列化时,Serialize方法利用反射来查看每个对象的类型中都有哪些实例字段。在这些字段中,任何一个引用了其他对象,格式化器的Serialize方法就知道哪些对象也要序列化。

格式化器的算法非常智能。它们知道如何确保对象图中的每个对象都只序列化一次。换言之,如果对象图的两个对象相互引用,格式化器就会检测到这一点,每个对象都只序列化一次,避免进入无限循环。

在上诉代码的SerializerToMemory方法中,当格式化器的Serialize方法返回后,MemoryStream直接返回给调用者。应用程序可以按照自己希望的任何方式利用这个字节数组的内容。例如,可以把他保存到一个文件中,复制到剪切板中或者通过网络发送等。

DeserializerFromMemory方法将一个流反序列化成一个对象图。该方法比用于序列化对象图的方法更简单。在代码中,我构造了一个BinaryFormatter,然后调用它的Deserialize方法。这个方法获取流作为参数,返回对反序列化好的对象图中的根对象的一个引用。

注意:下面是一个有趣而使用的方法,它利用序列化创建对象的一个拷贝(或者说一个克隆体):

  private static Object DeepClone(Object original)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Context = new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone);
                //将对象图序列化到内存流中
                formatter.Serialize(stream,original);
                //反序列化前,定为到内存流的起始位置
                stream.Position = 0;
                //将对象图反序列化成一组新对象,并且向调用者返回对象图的根(深拷贝)
                return formatter.Deserialize(stream);
            }
        }

在内部,格式化器的Deserialize方法会检查流的内容,构造流中所有对象的实例,并初始化这些对象的所有字段,使他们具有和当初序列化时相同的值,通常将Deserialize方法返回的对象引用转型为应用程序期待的类型。

在这个时候,我觉得有必要补充几点注意事项。首先,是由你来保证代码为序列化和反序列化使用相同的格式化器。例如,不要写代码用SoapFormatter序列化一个对象,再用BinaryFormatter反序列化。如果Deserialize发现自己解释不了一个流的内容,就会抛出一个System.Runtime.Serialization.SerializationException异常。

其次,可将多个对象图序列化到一个流中,这是很有用的一个操作。例如,假如有以下两个类定义:

  [Serializable]    sealed class Customer { }
  [Serializable]    sealed class Order { }

然后,在应用程序的主要类中,定义了以下静态字段:

private static List<Customer> s_customers = new List<Customer>();
        private static List<Order> s_pendingOrders = new List<Order>();
        private static List<Order> s_processedOrders = new List<Order>();

现在,可以利用如下所示的一个方法,将应用程序的状态序列化到单个流中:

 private static void SaveApplicationState(Stream stream)
        {
            BinaryFormatter binary = new BinaryFormatter();
            //序列化我们的应用程序的完整状态
            binary.Serialize(stream, s_customers);
            binary.Serialize(stream, s_pendingOrders);
            binary.Serialize(stream, s_processedOrders);
        }

  

为了重新构建应用程序状态,可以使用如下所示的一个方法发序列化状态:

private static void RestoreApplicationState(Stream stream)
        {
            BinaryFormatter binary = new BinaryFormatter();
            //反序列化我们应用程序的完整状态(和序列化的顺序一样)
            s_customers = (List<Customer>)binary.Deserialize(stream);
            s_pendingOrders = (List<Order>)binary.Deserialize(stream);
            s_processedOrders = (List<Order>)binary.Deserialize(stream);
        }

第三也是最后一点注意事项与程序集有关。序列化一个对象时,类型的全名和类型的定义程序集的名称会被写入流。默认情况下,BinaryFormatter会输出程序集的完整标识符,其中包含程序集的文件名(无扩展名),版本号,语言文化以及公钥信息。反序列化一个对象向时,格式化器首先获取程序集标识信息,并通过调用Assembly的Load方法,确保程序集以加载到正在执行的AppDomain。

程序集加载之后,格式化器在程序集中查找与要反序列化的对象匹配的一个类型。如果程序集不包含一个匹配的类型,就抛出一个异常,不再对更多的对象序列化。如果找到一个匹配的类型,就创建类型的一个实例,并用流中包含的值对其字段进行初始化。如果类型中的字段与流中读取的字段名不完全匹配,就抛出一个异常,不再对更多的对象进行序列化。

时间: 2024-10-17 14:17:55

第一节:序列化和反序列化快速入门的相关文章

Hibernate学习---第一节:hibernate配置和入门程序

一.ORM 简介: ORM 全称是 Object\ Relation Mapping, 即对象\关系映射 ORM 可以理解为一种规范,具体的 ORM 框架可作为应用程序和数据库的桥梁 面向对象程序设计语言与关系型数据库发展不同步时,需要一种中间解决方案,ORM 框架就是这样的解决方案 ORM 不是具体的产品,是一类框架的总称,基本特征: (1).完成面向对象的程序设计语言到关系数据库的映射 (2).基于 ORM 框架完成映射后,即可利用面向对象程序设计语言的简单易用性,又可利用关系型数据库的技术

【第一篇】spring boot 快速入门

1.开发环境 开发工具:IDEA2018.2.1 JDK:1.9 Maven : 3.3.9 操作系统:window 7 / window 10 2.项目结构 3.详细步骤 3.1 使用IDEA新建Maven空白项目 file->new->project,然后按照要求填好.如下: 点击finsh后会生成项目如下: 3.2 在pom.xml文件添加继承.依赖和插件配置 <!-- 默认继承 --> <parent> <groupId>org.springfram

[.net 面向对象程序设计进阶] (12) 序列化(Serialization)(四) 快速掌握JSON的序列化和反序列化

[.net 面向对象程序设计进阶] (12) 序列化(Serialization)(四) 快速掌握JSON的序列化和反序列化 本节导读: 介绍JSON的结构,在JS中的使用.重点说明JSON如何在.NET中快带序列化和反序列化.最后介绍在使用.NET序列化JSON过程中的注意事项. 读前必备: A.泛型       [.net 面向对象编程基础]  (18) 泛型 B.LINQ使用  [.net 面向对象编程基础] (20) LINQ使用 1. 关于JSON JSON的全称是”JavaScrip

火云开发课堂 - 《Shader从入门到精通》系列 第一节:Shader介绍与工程搭建

<Shader从入门到精通>系列在线课程 第一节:Shader介绍与工程搭建 视频地址:http://edu.csdn.net/course/detail/1441/22665?auto_start=1 交流论坛:http://www.firestonegames.com/bbs/forum.php 工程下载地址:请成为正式学员获取工程 课程截图: 项目实例: 版权声明:本文为博主原创文章,未经博主允许不得转载.

第一节,C语言入门

1.标示符:    命名规则:    1.只能由字母.数字.下划线组成    2.不能数字开头    3.不能与关键字重名    4.严格区分大小写    命名规范:     1.起一个有意义名字     2.驼峰标示2.注释 注释: 对代码的解释说明,是写给程序看的,方面程序员之间交流 特点: 注释是不参与编译 /* 这里面可以写 */ 多行注释 // 这是一个单行注释 只有这一行是注释,只有 两个斜杠后面才是注释内容 /* */ command + / 注释或取消注释 多行注释是可以嵌套单行

第一章 快速入门

C++ Primer 中文版,第4版 /* 第一章 快速入门第二章 变量和基本类型第三章 标准库类型第四章 数组和指针第五章 表达式第六章 语句第七章 函数第八章 标准IO库第九章 顺序容器第十章 关联容器第11章 泛型算法 第12章 类 第13章 复制控制 第14章 重载操作符与转换第15章 面向对象编程第16章 模板和泛型编程第17章 用于大型程序的工具第18章 特殊工具与技术 */ /* 第一部分:基本语言------------------------------------------

Python学习基础篇第一篇——快速入门(适合初学者)

一.Python学习基础篇第一篇--(快速入门) 建议从Python2.7开始学习,Python2.7可以支持扩展大量的第三方类库,是目前比较成熟的版本 编写代码的软件推荐将python自带的IDLE和PyCharm集成IDE结合起来使用 1.1 Python命令行 Python命令行将以 >>> 开始,比如 >>>print 'Hello World!' 对于验证简单的命令可以在python自带的IDLE中完成  1.2 在Python自带的IDLE写一段小程序 在所

Spring的快速入门第一天

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.06.21 lutianfei none 本文内容 Spring框架的概述 Spring的快速入门 Spring 工厂接口 在MyEclipse 配置Spring的xml文件提示 IoC容器装配Bean(xml配置方式) Ioc容器装配Bean(注解方式) 在web项目中集成Spring Spring 整合 junit4 测试 Spring框架学习路线 Spring的Ioc Spring的AOP , AspectJ S

【第一篇】ASP.NET MVC快速入门之数据库操作(MVC5+EF6)

目录 [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策略(MVC5+EF6) [第四篇]ASP.NET MVC快速入门之完整示例(MVC5+EF6) 请关注三石的博客:http://cnblogs.com/sanshi 新建项目 打开VS2015,找到菜单项[文件->新建->项目],打开向导对话框: 注意我们的选择项: 1.     运行平台:.NET FrameWork 4.5 2.     项目模板:ASP.NET W