一.序列介绍     

      将对象及其状态保存起来,就称为序列化(Serialization),最简单和常见的一种情况就是将对象及其状态保存在文件中或者数据库字段中;而反序列化(Deserialzation)是序列化的反向操作,将文件还原为对象,方便使用。

使用序列化的原因:将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本;按值将对象从一个应用程序域发送至另一个应用程序域;主要用于通信。方便不同客户端之间数据的识别。例如,序列化可用于在 ASP.NET 中保存会话状态,以及将对象复制到 Windows 窗体的剪贴板中。它还可用于按值将对象从一个应用程序域远程传递至另一个应用程序域。本文简要介绍了 Microsoft .NET 中使用的序列化。

有几种作用:
1:可以将对象序列化到XML.也可以称为持久化..
  例如:你要保存一个用户的某种设置,而且应用程序再将一直使用用户的这种设置.那么你在内存中的对象关机后不能被保存了.所以将这个对象序列化到一个XML文件就记录住了.
2:可以将其序列化后,方便在网络上传输..
  例如:remoting中数据传输.......

3:在不同的AppDomain或进程之间传递数据 ,也就是跨平台。不同客户端通讯。

4:在分布式应用系统中传递数据


二.几种序列化技术

   在C#中常见的序列化的方法主要也有三个:BinaryFormatter、SoapFormatter、XML序列化。

   BinaryFormatter用于将对象序列化为二进制数据;

   SoapFormatter用于将对象序列化为人类直接可以读的文本;--据说慢慢被微软淘汰,因为不能处理泛型。

   XML序列化用于将对象序列化为Xml的存储格式;

二进制序列化保持类型保真度,这对于在应用程序的不同调用之间保留对象的状态很有用。例如,通过将对象序列化到剪贴板,可在不同的应用程序之间共享对象。您可以将对象序列化到流、磁盘、内存和网络等等。远程处理使用序列化“通过值”在计算机或应用程序域之间传递对象。

XML 序列化仅序列化公共属性和字段,且不保持类型保真度。当您要提供或使用数据而不限制使用该数据的应用程序时,这一点是很有用的。由于 XML 是一个开放式标准,因此,对于通过 Web 共享数据而言,这是一个很好的选择。SOAP 同样是一个开放式标准,这使它也成为一个颇具吸引力的选择。

使用提供的数据协定,将类型实例序列化和反序列化为 XML 流或文档(或者JSON格式)。常应用于WCF通信。


三.Net中实现序列化

  .Net提供了一个接口(IFormatter)来实现序列化和反序列化的操作。这个接口有两个重要的方法Serialize()和Deserialize().由于它们接收的是Stream基类,因此可以序列化到任何流类型中,不仅限于文件流。并且提供了两个实现这个接口的类BinaryFormatter和SoapFormatter。

比如:

using System.IO;
using System.Runtime.Serialization.Formatters.Bindary;

[Serializable]
public class Person
{
    private  int  id;
    public string name {get;set;}
    public double price{get;set;}
    public Person(int id)
    {
            this.id=id;
    }
    punlic override string ToString()
    {
        return String.Format("ID:{0},Name:{1},Price:{2}",this.id,this.name,this.price);
     }
}    
   //序列化
  public void SerialzeNow()
{
     Person person=new Person(2) { Name="小张",Price=4998.53};
     FileStream fs=new FileStream("D:\\temp.dat",FileMode.Create,FileAccess.Write,FileShare.None);
     BinaryFormatter bf=new BinaryFormatter();
     bf.Serialize(fs,person);
     fs.Close();
      Console.WriteLine("序列化后:"+person);
}
//反序列化
public void DeSerializeNow()
{
 Person person=new Person();
     FileStream fs=new FileStream("D:\\temp.dat",FileMode.Open,FileAccess.Read,FileShare.Read);
     BinaryFormatter bf=new BinaryFormatter();
Person ;
    // Console.WriteLine(person.id);  单独访问的话,person.id是访问不到的
    // Console.WriteLine(person.name);
Console.WriteLine(person.price);
     Console.WriteLine("反序列后:"+person);
     fs.Close();
}

反序列化输出结果为:ID:2,Name:小张,Price:4998.53

注意红色部分代码,虽然字段int是私有的,但是可以将它序列化,这是因为序列化的底层是通过反射来实现的,而反射可以访问到私有字段。

    

   选择性序列化

   类通常包含不应被序列化的字段。例如,假设某个类用一个成员变量来存储线程 ID。当此类被反序列化时,序列化此类时所存储的 ID 对应的线程可能不再运行,所以对这个值进行序列化没有意义。可以通过使用 NonSerialized 属性标记成员变量来防止它们被序列化。


    比如在上面的代码添加部分代码



[Serializable]
public class Person
{
    private  int  id;
    public string name {get;set;}
    public double price{get;set;}
    [NonSerialized]
    private string sextype;
    public Person(int id)
    {
            this.id=id;
             sextype="男";
    }
    punlic override string ToString()
    {
        return String.Format("ID:{0},Name:{1},Price:{2},SexType:                  {3}",this.id,this.name,this.price,this.sextype==null?"NULL":this.sextype);
     }
}



ID:2,Name:小张, Price:4998.53,SexType:男



          反序列化后:ID:2,Name:小张,Price:4998.53,SexType:为空



尽管反序列化没有抛出任何异常,还是发现SexType的值变成了 为空。这是因为反序列化并不会调用对象的构造函数。此时,由于Conn没有进行序列化,使序列化前对象和反序列化后得到对象的状态变的不一致了。.Net中提供了IDeserializationCallBack接口来完成事件:



public interface IDeserializationCallBack
 
 
    {   void OnDeserialization(object sender);          }



   从接口名称中的Callback可以看出,这个接口是一个回调函数,在对象反序列化后调用。sender参数总是传入null,现在让Person实现这个接口,以实现sextype实例化



[Serializable]
 
 
public class Product:IDeserializationCallback
 
 
{
 
 
     //其它代码省略
 
 
void OnDeserialization(object sender)
 
 
     {
 
 
            this.sextype="男";
 
 
     }
 
 
}



结果就是:ID:2,Name:小张,Price:4998.53,SexType:男。





XML 序列化方式也是一样的,只不过最后保存的格式是XML。这里就不做例子呢。