详细序列化和反序列化笔记
序列化概念:
按值封送:将对象从一个应用程序域传输到另一个应用程序域,居然后反序列化,以便第二个应用程序域中生成该对象的一个精确副本。
如果对象从MarshalByRefObject派生,则将对象引用从一个应用程序域传递到另一个。
自定义序列化的安全问题:
序列化可以允许其他代码查看或修改用其他方式无法访问的对象数据。因此执行序列化的代码需要制定SerializationFormatter标识的SecurityPermission。默认情况下,网络下载的代码不会授予该权限,只有本地计算机上的代码才被授予该权限,必须采用下列方式保护GetObjectData方法:要求使用具有指定SerializationFormatter标志的SecurityPermission;或要求具备专门用于帮助保护私有数据的其他权限。
版本容错序列化VTS:
二进制序列化和Soap序列化均会启用VTS,在反序列化时,忽略所有外来或意外数据而导致的异常。OptionalFieldAttribute特性修饰字段,可将字段标记为可选,反序列化期间,因缺少数据无法对该字段进行反序列化时,此确实将会被忽略。
OptionalFieldAttribute特性的属性VersionAdded用于标记类的版本,应当在每次修改类型时,版本应该正好增加1,鉴于这一属性未在.Net Framework2.0中使用,该版本号应该从2开始。
使用SerializationBinder控制序列化和反序列化:
序列化过程中,格式化程序传输创建正确类型和版本的对象实例所需要的信息,包括对象的完整名称和程序集名称。默认情况下反序列化可使用此信息创建相同对象实例。
但由于原始类可能在执行反序列化的计算机上不存在,原始类已经在程序集之间移动或服务器与客户端要求使用不同的版本,因此用户可能需要控制序列化和反序列化的具体类。子功能只能在使用BinaryFormatter和NetDataContractSerializer时使用。
此功能需要继承抽象类SerializationBinder并重写方法BindToName和BindToType(必须重写,此方法传入的参数是被序列化的类的程序集名称和类型的完全限定名)。
序列化最佳实践:
切勿移除已序列化的字段。
如果旧版本未使用NoSerializedAttribute修饰字段,则新版本也不应该使用。
切勿修改已序列化字段的名称或类型。
如果添加新的字段,应使用OptionalFieldAttribute特性修饰。
移除NonSerializedAttribute修饰的字段应使用OptionalFieldAttribute修饰。
对于不能接受0或null作为默认值的字段,应使用序列化回调设置有意义的默认值。
如果要确保类型与将来的序列化引擎的兼容应始终使用OptionalFieldAttribute的VersionAdded属性设置版本,并避免版本分支。
C#的序列化分为二进制序列化,Soap序列化,XML序列化。
工具类:
二进制序列化将对象序列化为二进制格式,使用System.Runtime.Serialization.Formatters.Binary.BinaryFormatter类进行。
Soap序列化将对象序列化为符合SOAP协议传输的数据格式,使用System.Runtime.Serialization.Formatters.Soap.SoapFormatter类进行。
XML序列化将对象序列化为XML数据,使用System.Xml.Serialization.XmlSerializer类实现。
序列化方式的不同:
二进制序列化与Soap序列化将对象的可序列化的公共或私有字段序列化,XML序列化仅仅将公共字段或属性进行序列化。
二进制序列化会将类的完全限定名与程序集完整名称(项目名称,版本,公钥标记,区域性等)进行序列化。
Soap序列化使用XML命名空间序列化原始程序集信息。
XML序列化不保存限定名和程序集名称,但XML的反序列化仍旧无法序列化为同成员的其他的类。XML序列化需要制定序列化对象的类型。
SerializableAttribute特性相关说明:
需要持久化的类必须使用SerializableAttribute特性修饰,可选择性的使用NonSerializedAttribute特性修饰不需要序列化的属性或字段。
但在使用XML序列化时不需要SerializableAttribute特性修饰,但要求必须一个无参构造方法。
二进制序列化与Soap序列化:
另见简单序列化和反序列化笔记。
注意:Soap序列化不支持泛型。
XML序列化:
XML序列化不需要SerializableAttribute特性修饰被序列化的类,但要求必须具有无参构造函数。
XML只能序列化公开的属性或字段,被序列化的属性或字段如果没有显示使用特性修饰,则除集合属性或字段外,普通属性或字段默认使用XmlElementAttribute特性修饰,集合类默认使用XmlArrayAttribute修饰。
对象中使用XmlTextAttribute修饰的属性或对象将被序列化为父元素的文本子节点而不是元素子节点。
XmlElementAttribute可用于修改被修饰的属性或字段序列化后的元素名称,该特性的属性Order可用于指定被修饰属性或字段序列化成xml元素后出现的顺序。
类使用XmlTypeAttribute修饰可用于类修改序列化后的对应的元素的名称。
类属性使用XmlAttributeAttribute特性可将属性或字段序列化为父元素的xml属性。
XmlArrayAttribute特性可修改修饰的集合成员对应的元素的名称,集合属性如果被XmlElementAttribute特性修饰,则等同于使用该特性修饰集合属性的每一个元素,例如:
public class WomanWithFriend
{
//[XmlArray("朋友们")]
//[XmlArrayItem("朋友")]
[XmlElement]
public List<Woman> Friends { get; set; }
public Woman Self { get; set; }
}
public class Woman
{
public string WomanName { get; set; }
public int Age { get; set; }
public string Description { get; set; }
}
//使用XmlElement修饰的结果:
<?xml version="1.0" encoding="utf-8"?>
<WomanWithFriend xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Friends>
<WomanName>friend1</WomanName>
<Age>12</Age>
<Description>This is first friend</Description>
</Friends>
<Friends>
<WomanName>friend2</WomanName>
<Age>13</Age>
<Description>This is second friend</Description>
</Friends>
<Self>
<WomanName>woman self</WomanName>
<Age>13</Age>
<Description>This is self</Description>
</Self>
</WomanWithFriend>
//不使用XmlElement使用XmlArray和XMLArrayItem修饰的结果:
<?xml version="1.0" encoding="utf-8"?>
<WomanWithFriend xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<朋友们>
<朋友>
<WomanName>friend1</WomanName>
<Age>12</Age>
<Description>This is first friend</Description>
</朋友>
<朋友>
<WomanName>friend2</WomanName>
<Age>13</Age>
<Description>This is second friend</Description>
</朋友>
</朋友们>
<Self>
<WomanName>woman self</WomanName>
<Age>13</Age>
<Description>This is self</Description>
</Self>
</WomanWithFriend>
XmlArrayItemAttribute特性可修改被修饰的集合成员的元素对应的xml元素的名称,作为集合属性元素的类的XmlTypeAttribute设置的xml元素名称会被覆盖,该特性的构造函数可传递Type值,以便对集合类型的属性使用多态时(集合属性指定为基类,但集合的元素是至少一种派生类)指定集合类型的属性的元素的类型有哪些(每一个XmlArrayItemAttribute指定一种派生类,如果集合属性的元素具有多个派生类,则应使用多个XmlArrayItemAttribute特性)。
被XmlIgnoreAttribute修饰的属性或字段不会被序列化。
XmlRootAttribute修饰类可用于设置序列化的根节点的属性。
Xml序列化的自定义使用IXmlSerializable接口,通过XmlReader和XmlWriter来进行序列化和反序列化的过程,代码示例:
public class CustomerXmlSerializable : IXmlSerializable
{
public string Name;
public System.Xml.Schema.XmlSchema GetSchema()//不知晓
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
Name = reader.GetAttribute("名称");
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString("名称", Name);
}
}
//修改日期2015-09-20