原文链接:https://blog.csdn.net/wanlong360599336/article/details/9222459

浅析.NET中的Serialization

摘要 本文简要介绍了.NET中的序列化(Serialization)概念,以及在代码中实作Serialization的方法。文章的最后介绍了Serialization在Clone方法中的运用。 
   
   
   
  Serialization的概念 
   
   
   
  Serialization是.NET中一种实现对象持久性(Persistent)的机制。它是一个将对象中的数据转换成一个单一元素(通常是Stream)的过程。它的逆过程是Deserialization。Serialization的核心概念是将一个对象的所有数据看作一个独立的单元。 
   
   
   
  一般说来,在两种情况下非常需要Serialization:1)当我们希望能够将对象当前的状态完整地保存到存储介质中,以便我们以后能够精确地还原对象时;2)当我们希望将对象从一个应用程序空间(Application domain)传递到另一个应用程序空间时。例如,Windows Form程序就是利用Serialization机制来实现剪贴板的copy & paste的。 
   
   
   
  .NET Framework支持两种类型的Serialization:Shallow Serialization和Deep Serialization。 
   
   
   
  所谓Shallow Serialization是将对象的可读写(read-write)属性的值转换成字节流,而对象内部的数据(没有通过read-write属性暴露出来的数据)则不被转换。XmlSerializer以及Web Services就使用这种技术。

Deep Serialization比Shallow Serialization更加彻底,因为它是将存储在对象私有变量里的实际值拷贝到字节流里。而且Deep Serialization还将serialize整个object graph。也就是说,如果你的对象持有其他对象的引用,或者其他对象引用的集合,那么所有这些对象都将被Serialize。BinaryFormatter和SoapFormatter以及.NET Remoting都使用Deep Serialization技术,它甚至被有限地用于LosFormatter来产生存储在Web Form页中的状态数据。

本文将着重于Deep Serialization。 
   
   
   
  Serialization的过程 
   
   
   
  .NET Framework通过Reflection提供自动Serialization的机制。当一个对象被序列化(Serialized)的时候,它的类名,Assembly,以及类实例的所有数据成员都将被写入存储介质中。Serialization引擎保持对所有已经被序列化的对象引用的追踪,以确保相同的对象引用最多只被序列化一次。 
   
   
   
  通常,一个Serialization过程会由formatter(例如BinaryFormatter)的Serialize方法引发。对象的Serialization过程按照以下规则进行: 
   
  1、 检测以确保formatter是否拥有一个代理选择器(surrogate selector)。如果有,检查代理选择器是否持有给定的对象类型。如果有,ISerializable.GetObjectData被调用。 
   
  2、 如果formatter没有代理选择器,或者代理选择器没有对象类型,检查对象是否被用Serializable属性标记。如果没有,则抛出SerializationException异常。 
   
  3、 如果对象被标记为Serializable,检查对象是否实现了ISerializable接口。如果实现了此接口,则GetObjectData被调用。 
   
  4、 如果对象没有实现ISerializable接口,则使用默认的序列化策略,来序列化没有用NonSerialized属性标记的域。 
   
   
   
  使你的class能够被序列化 
   
   
   
  通过上面对Serialization过程的分析,我们可以看出,有两种方式可以使一个class能够被序列化:1)将此class简单地标记为Serializable;2)为此class实现ISerializable接口,并将此class标记为Serializable。

1、 标记Serializable属性 
   
   
   
  标记Serializable属性的方式是实现Serialization的基本方法。举个简单的例子:

   [Serializable] 

   public class Person 

   { 

   public string name = null; 

   public int age = ; 

   } 

你可以使用BinaryFormatter来将上面的class序列化:

   Person sam = new Person(); 

   sam.name = "sam"; 

   sam.age = ; 

   IFormatter formatter = new BinaryFormatter(); 

   Stream stream = new FileStream("sam.dat", 

   FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, sam); stream.Close();

就是这么简单,你所要做的就是创建一个Stream和一个formatter的实例,然后调用formatter的Serialize方法。经过BinaryFormatter serialize的数据仍然能够通过BinaryFormatter deserialize回来,方法与serialize同样简单,这里就不赘述了。 
   
   
   
  如果你不想将类里的所有域都序列化,可以使用NonSerialized属性进行选择。如:

 [Serializable] 

   public class Person 

   { 

   public string name = null; 

   [NonSerialized] 

   public int age = ; 

   }
   

这样,age域就不会被序列化了。 
   
   
   
  需要注意的是,Serializable属性并不能被继承。也就是说如果你希望Person的派生类也能够被Serialize的话,那么这个派生类也必须被Serializable标记。否则将得到SerializationException异常。

同样的,Person类中的所有对其他类的引用,其所引用的类都应该是能够被Serialize的。.NET Framework中的大部分class都实现了ISerializable接口,但有些class没有实现,例如ImageList。可以通过MSDN Library的到一个实现了ISerializable接口的class列表。对那些没有实现此接口的class,使用的时候要当心。 
   
   
   
  2、 实现ISerializable接口 
   
   
   
  Serializable属性的功能非常强大,它使得Serialize和Deserialize变得十分简单。但凡事有利必有弊,由Serializable实现的自动序列化方法有时不够灵活。我们并不能完全控制Serialize和Deserialize的行为,而有些时候它们的行为对我们来说很重要。那么我们通过何种方法能够控制Serialize和Deserialize的行为呢?答案就是,自己来实现ISerializable接口。ISerializable接口给予我们更大的自由来控制Serialize和Deserialize,但是无疑我们将不得不写更多的代码L。 
   
   
   
  下面我们来看看如何实现ISerializabe接口。ISerializable接口位于System.Runtime.Serialization名字空间中,声明如下:

   public inferface ISerializable 

   { 

   void GetObjectData(SerializationInfo info, 

   StreamingContext context); 

   } 

它只有一个方法GetObjectData。因此,像实现其他接口一样,我们必须实现此方法。但与其他接口不同的是,为了Deserialization,我们还必须实现一个特殊的构造函数(我称此构造函数为“序列化构造函数”),此构造函数具有与GetObjectData相同的参数列表。由于此构造函数专门用于.NET Framework在Deserialize时的Reflection机制,因此我们通常将它声明为保护或私有模式。如下:(当然,如果你的class只需要Serialize而不需要Deserialize的话,也可以不实现这个特殊的构造函数)

   [Serializable] 

   public class Person : ISerializable 

   { 

   public string name = null; 

   public int age = ; 

   public Person() 

   { 

   } 

   protected Person(SerializationInfo info, StreamingContext context) 

   { 

   name = info.GetString("name"); 

   age = info.GetInt32("age"); 

   } 

void ISerializable.GetObjectData(SerializationInfo info, 

   StreamingContext context) 

   { 

   info.AddValue("name", name); 

   info.AddValue("age", age); 

   } 

   }
   

通过实现ISerializable接口,使得我们有机会在ISerializable.GetObjectData中控制Serialize的行为,在“序列化构造函数”中控制Deserialize的行为。这个接口提供给我们的信息非常全面而灵活,以致于我们甚至可以在这两个方法中耍些花招。比如,我们可以在Deserialize的时候,籍由改变info.FullTypeName来得到一种与被Serialize的对象不同类型的另一个对象等。 
   
   
   
  独辟蹊径 
   
   
   
  前面谈到过Serialization被运用的典型环境,是对象存储、进程间数据传递等涉及到对象持久性的领域。但实际上,它也能够被运用到其他的许多地方,关键在于我们是否能想到去用运Serialization,有时候思维定式也是很可怕的J。举个例子,我们来看看在Clone方法中如何使用Serialization[1]。 
   
   
   
  如果我们要为Person类实现Clone方法,我们通常会这样写:

[Serializable] 

   public class Person : ICloneable 

   { 

   public string name = null; 

   public int age = ; 

   public object Clone() 

   { 

   Person person = new Person(); 

   person.name = name; 

   person.age = age; 

   return person; 

   } 

   } 

如果我们利用Serialization的方法,Clone函数就能写成下面的样子:

public object Clone() 

   { 

   MemoryStream stream = new MemoryStream(); 

   BinaryFormatter formatter = new BinaryFormatter(); 

   formatter.Serialize(stream, this); 

   stream.Position = ; 

   return formatter.Deserialize(stream); 

   }
   

从这两个实现上看,使用Serialization实现Clone方法似乎并没有什么好处。可是设想如果你面对的是一个复杂的类继承体系,从基类到派生类都需要实现Clone方法。利用第一种实作手法,你将不得不为每一个class写一个Clone方法,而且随着数据成员的增多,这个方法将越来越冗长,并且会由于数据成员的改变而引发错误(我曾经遇到过好几次,由于class中增加了成员变量,而Clone方法没有及时更新,导致运行时错误。呵呵,这种错误还很难调试)。现在你看到用Serialization实现的好处了吧?是的,我们只要在基类中将Clone方法声明为virtual,并用Serialization的方法实现之,然后保证基类和派生类都可以被Serialize,上面所有的麻烦不都迎刃而解了吗? 
   
   
   
  总结 
   
   
   
  现代软件项目中,无论何种项目都会或多或少地涉及到对象持久性的问题,.NET也不例外,无论是Windows Form、ASP.NET,还是Web Services,都需要处理对象持久性。而Serialization正是.NET为应对这个问题而给出的解法。

参考文献 
   
   
   
  ·[1] Rockford Lhotka,《Object Serialization in Visual Basic .NET》,MSDN Library。Serialization在Clone方法中的运用即来自此文。 
   
   
   
  ·Piet Obermeyer and Jonathan Hawkins,《Object Serialization in the .NET Framework》,MSDN Library。

例如这边用二进制来序列化和反序列化:

        /// <summary>
/// 二进制序列化
/// </summary>
/// <param name="mySerializ">对象</param>
/// <param name="Path">路径</param>
public static void BinarySerializ(CaseInfo mySerializ,string Path)
{
using (FileStream stream = new FileStream(Path, FileMode.Create, FileAccess.Write))
{
BinaryFormatter binary = new BinaryFormatter();
binary.Serialize(stream, mySerializ);
}
} /// <summary>
/// 二进制反序列化
/// </summary>
public static CaseInfo BinaryDeserializ(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
BinaryFormatter binary = new BinaryFormatter();
CaseInfo mySerializ = (CaseInfo)binary.Deserialize(stream);
return mySerializ;
}
}

.net中[Serializable]序列化的应用的更多相关文章

  1. 【转】C#中Serializable序列化实例详解

    这篇文章主要介绍了C#中Serializable序列化,以实例形式详细讲述了系列化的技术及各种序列化方法,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了C#中Serializable序列化.分 ...

  2. C#中Serializable序列化

    序列化就是是将对象转换为容易传输的格式的过程,一般情况下转化打流文件,放入内存或者IO文件 中.例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象,或 ...

  3. Android中Serializable和Parcelable序列化对象详解

    学习内容: 1.序列化的目的 2.Android中序列化的两种方式 3.Parcelable与Serializable的性能比较 4.Android中如何使用Parcelable进行序列化操作 5.P ...

  4. C#中JSON序列化和反序列化

    有一段时间没有到博客园写技术博客了,不过每天逛逛博客园中大牛的博客还是有的,学无止境…… 最近在写些调用他人接口的程序,用到了大量的JSON.XML序列化和反序列化,今天就来总结下json的序列化和反 ...

  5. java.io.Serializable 序列化问题

    java.io.Serializable 序列化问题 Person.java package a.b.c; public class Person implements java.io.Seriali ...

  6. .net中对象序列化技术浅谈

    .net中对象序列化技术浅谈 2009-03-11 阅读2756评论2 序列化是将对象状态转换为可保持或传输的格式的过程.与序列化相对的是反序列化,它将流转换为对象.这两个过程结合起来,可以轻松地存储 ...

  7. java中serializable

    java中serializable是一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才是可序列化的.因此如果要序列化某些类的对象,这些类就必须实现Serializable接 ...

  8. c# 与 Unity3d 中的序列化

    圣典中对于Unity3D的序列化介绍很容易和C#的序列化介绍搞混,做个笔记,方便以后查找. 很多资料算是拾人牙慧. 一.Serializable 序列化 Inherits from Attribute ...

  9. Serializable序列化的作用

    这里转载一篇讲解java序列化(Serializable)和反序列化方面的感觉很好的文章.1.序列化是干什么的?简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的 ...

随机推荐

  1. 【AMAD】jsonschema -- (又)一个JSON Schema的Python实现

    动机 简介 用法 个人评分 动机 JSON Schema1是一个专业词汇,可以让你注解和验证JSON文档. 使用JSON Schema的好处有: 描述你的数据格式 提供清晰的易读的文档 验证数据: 用 ...

  2. 神经网络中batch_size参数的含义及设置方法

    本文作者Key,博客园主页:https://home.cnblogs.com/u/key1994/ 本内容为个人原创作品,转载请注明出处或联系:zhengzha16@163.com 在进行神经网络训练 ...

  3. Lombok的使用与原理

        在面向对象编程中必不可少需要在代码中定义对象模型,而在基于Java的业务平台开发实践中尤其如此.相信大家在平时开发中也深有感触,本来是没有多少代码开发量的,但是因为定义的业务模型对象比较多,而 ...

  4. [转帖]yum命令的使用与createrepo自建仓库教程

    yum命令的使用与createrepo自建仓库教程 http://www.linuxe.cn/post-300.html 跟上篇一样 可以学习一下. 发布:TangLu2018-11-23 16:48 ...

  5. Python字典推导式将cookie字符串转化为字典

    Python中的列表推导式一般是大家所熟悉的,可以极大的简洁代码:而Python中的字典推导式和列表推导式也是大同小异的 cookie: PHPSESSID=et4a33og7nbftv60j3v9m ...

  6. Python 条件判断 和循环

    使用条件判断 if else # 条件派单 if else print('条件派单 if else') # s = input('请输入生日年号:') # birth = int(s) birth = ...

  7. AppCan IDE中有时格式化代码后,代码就运行不了了。

    AppCan IDE中有时格式化代码后,代码就运行不了了.

  8. 从入门到自闭之Python序列化

    序列化(背) json :将数据类型转换成字符串(序列化),将字符串装换成原数据类型(反序列),支持dict,list,tuple等,序列后都变成了列表 dumps,loads ------ 用于网络 ...

  9. CF1151F Sonya and Informatics

    cf luogu 我们最终要的序列一定是前面全是0,后面全是1,假设总共\(m\)个0,那么这等价于前\(m\)位0的个数为\(m\).当然一开始可能数量没有\(m\) 那就把前\(m\)位0的数量作 ...

  10. cube-ui indexList的正确使用

    demo地址:https://github.com/zphtown/cube-ui-bug 上拉和下拉核心代码: onPullingDown () { this.isNoMore = false th ...