惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
V
Vulnerabilities – Threatpost
TaoSecurity Blog
TaoSecurity Blog
C
Cybersecurity and Infrastructure Security Agency CISA
P
Proofpoint News Feed
G
GRAHAM CLULEY
S
Securelist
P
Palo Alto Networks Blog
MongoDB | Blog
MongoDB | Blog
A
Arctic Wolf
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
WordPress大学
WordPress大学
Project Zero
Project Zero
T
Threat Research - Cisco Blogs
L
Lohrmann on Cybersecurity
C
Cyber Attacks, Cyber Crime and Cyber Security
F
Fortinet All Blogs
博客园 - 叶小钗
B
Blog RSS Feed
C
Cisco Blogs
Google DeepMind News
Google DeepMind News
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
G
Google Developers Blog
K
Kaspersky official blog
D
Docker
Latest news
Latest news
Cisco Talos Blog
Cisco Talos Blog
T
Tor Project blog
Cyberwarzone
Cyberwarzone
Security Latest
Security Latest
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Spread Privacy
Spread Privacy
Microsoft Azure Blog
Microsoft Azure Blog
C
Check Point Blog
J
Java Code Geeks
Simon Willison's Weblog
Simon Willison's Weblog
T
Tenable Blog
Recent Announcements
Recent Announcements
T
Tailwind CSS Blog
H
Help Net Security
L
LINUX DO - 热门话题
T
The Exploit Database - CXSecurity.com
Jina AI
Jina AI
S
SegmentFault 最新的问题
MyScale Blog
MyScale Blog
NISL@THU
NISL@THU
美团技术团队
腾讯CDC

博客园 - Freedom

ebook site XML Namespaces and How They Affect XPath and XSLT Debugging Applications for Microsoft .NET and Microsoft Windows: Notes-Books Debugging Applications for Microsoft .NET and Microsoft Windows: Notes-Prerequisites to Debugging Debugging Applications for Microsoft .NET and Microsoft Windows: Notes-The Debugging Process NET垃圾回收机制 A Software Developer’s Reading Plan #if (C# Reference) VS 2008 常用快捷键! One Day-XML:XML Schema 参考手册 One Day-XML:XSLT One Day-XML:WAP One Day-XML:Web Services One Day-XML:WSDL One Day-XML:RDF One Day-XML:RSS One Day-XML:XForms One Day-XML:SOAP One Day-XML:XML DOM
浅析.NET中的Serialization
Freedom · 2010-04-21 · via 博客园 - Freedom

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 = 0; 

  } 

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

  Person sam = new Person(); 

  sam.name = "sam"; 

  sam.age = 24; 

  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 = 0; 

  } 

  这样,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 = 0; 

  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的对象不同类型的另一个对象等。