码迷,mamicode.com
首页 > Windows程序 > 详细

C# 序列化和反序列化

时间:2017-05-13 11:08:42      阅读:301      评论:0      收藏:0      [点我收藏+]

标签:body   包含   value   key   graph   nfa   exce   out   nose   

 

  程序员在编写应用程序的时候往往要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上以实现通讯。这个将程序数据转化成能被存储并传输的格式的过程被称为"序列化"(Serialization),而它的逆过程则可被称为"反序列化"(Deserialization)。

 

  .Net框架对序列化机制具有非常好的支持,它提供了两个名字空间(namespace):System.Runtime.Serialization和System.Runtime.Serialization.Formatters以完成序列化机制的大部分功能。系列化这项技术可以应用在将程序产生的结果数据存储到文件系统中,但是它更主要的应用是在于.Net Remoting和Web服务的实现上。

 

  序列化机制的实现是依靠格式器(Formatter)而完成的,它是一个从System.Runtime.Serialization.IFormatter继承下来的类的对象。格式器完成了将程序数据转化到能被存储并传输的格式的工作,同时也完成了将数据转化回来的工作。.Net框架为程序员提供了两种类型的格式器,一种通常是应用于桌面类型的应用程序的,它一个是System.Runtime.Serialization.Formatters.Binary.BinaryFormatter类的对象,而另一种则更主要的应用于.Net Remoting和XML Web服务等领域的,它一个是System.Runtime.Serialization.Formatters.Soap.SoapFormatter类的对象。从它们的名称来看,我们不妨将它们分别称为二进制格式器和XML格式器。

 

  本文将从这两个格式器入手,先向大家介绍分别用它们如何实现序列化和反序列化,然后比较两种格式器的不同点。接着我会向大家介绍实现序列化对对象类型的一些要求,同时还要向大家介绍两种不同的序列化方式:基本序列化(Basic Serialization)和自定义序列化(Custom Serialization)。最后,我还会给大家介绍一个实例程序以加深大家对序列化机制的理解程度。

 

  一.二进制格式器(Binary Formatter) vs XML格式器(XML Formatter):

 

  下面我先向大家介绍两种不同的格式器,分别用它们如何实现序列化机制和反序列化机制,请看下面的代码:

 

 

#region Binary Serializers

public static System.IO.MemoryStream SerializeBinary(object request) {

 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer = 

  new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

 System.IO.MemoryStream memStream = new System.IO.MemoryStream();

 serializer.Serialize(memStream, request);

 return memStream;

}

 

public static object DeSerializeBinary(System.IO.MemoryStream memStream) {

 memStream.Position=0;

 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter deserializer = 

  new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

 object newobj = deserializer.Deserialize(memStream);

 memStream.Close();

 return newobj;

}

#endregion

 

#region XML Serializers

public static System.IO.MemoryStream SerializeSOAP(object request) {

 System.Runtime.Serialization.Formatters.Soap.SoapFormatter serializer = 

  new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();

 System.IO.MemoryStream memStream = new System.IO.MemoryStream();

 serializer.Serialize(memStream, request);

 return memStream;

}

 

public static object DeSerializeSOAP(System.IO.MemoryStream memStream) {

 object sr;

 System.Runtime.Serialization.Formatters.Soap.SoapFormatter deserializer = 

  new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();

 memStream.Position=0;

 sr = deserializer.Deserialize(memStream);

 memStream.Close();

 return sr;

}

#endregion

 

 

  从上面的代码我们可以发现无论运用哪种格式器,其基本的过程都是一样的,而且都是非常容易实现的,唯一的不同就是定义格式器的类型不同。不过在实际的应用中,二进制格式器往往应用于一般的桌面程序和网络通讯程序中,而XML格式器禀承了XML技术的优点,大多数被应用于.Net Remoting和XML Web服务等领域。下面我们来分析一下两种格式器各自的优点。

 

  二进制序列化的优点:

 

  1. 所有的类成员(包括只读的)都可以被序列化;

 

  2. 性能非常好。

 

  XML序列化的优点:

 

  1. 互操作性好;

 

  2. 不需要严格的二进制依赖;

 

  3. 可读性强。

 

  通过分析上面的代码,我们知道了选择二进制序列化的方式还是选择XML序列化的方式仅仅是对不同的格式器进行选择而已。你可以根据实际的需要选择相应的格式器完成序列化和反序列化工作。同时请注意,代码中的序列化函数和反序列化函数仅仅是在调用Serialize()和Deserialize()这两个核心函数上产生了差别,即它们的参数不同。因此以上的代码完成了一些最最基本但是很重要的功能,你可以将它们运用在你的程序中,或是将其进行适当扩充以满足程序的特定需要。

 

 

  二.序列化机制对类的要求:

 

  如果你要对一个对象进行序列化,那么你必须将它的类型标记为[Serializable()],该操作是通过SerializableAttribute属性来实现的。将SerializableAttribute属性应用于一种数据类型可表明该数据类型的实例可以被序列化。如果正在序列化的对象图中的任何类型未应用SerializableAttribute属性,公共语言运行库则会引发SerializationException。默认情况下,类型中由SerializableAttribute标记的所有公共和私有字段都会进行序列化,除非该类型实现ISerializable接口来重写序列化进程(通过实现该接口我们便可以实现将在后面介绍的"自定义序列化")。默认的序列化进程会排除用NonSerializedAttribute属性标记的字段,即你可以将该类型标记为[NonSerialized()]以表明它是不可以被序列化的。如果可序列化类型的字段包含指针、句柄或其他某些针对于特定环境的数据结构,并且不能在不同的环境中以有意义的方式重建,则最好将NonSerializedAttribute属性应用于该字段。有关序列化的更多信息,请参阅System.Runtime.Serialization名字空间中的相关内容。

 

  下面我给大家介绍一个例子,以显示如何正确的运用SerializableAttribute属性和NonSerializedAttribute属性。该程序中运用到了XML格式器,不过同时给出了二进制格式器为参考(程序中将其用"//"标注),其实现的结果是一样的。该程序实现的功能是在序列化和反序列化操作前后测试对象因包含了[NonSerialized()]的字段而显示不同的屏幕打印结果。其代码如下:

 

 

using System;

using System.IO;

using System.Runtime.Serialization;

using System.Runtime.Serialization.Formatters.Soap;

//using System.Runtime.Serialization.Formatters.Binary;

 

public class Test {

 public static void Main() {

  // 创建一个新的测试对象

  TestSimpleObject obj = new TestSimpleObject();

 

  Console.WriteLine("Before serialization the object contains: ");

  obj.Print();

 

  // 创建一个文件"data.xml"并将对象序列化后存储在其中

  Stream stream = File.Open("data.xml", FileMode.Create);

  SoapFormatter formatter = new SoapFormatter();

  //BinaryFormatter formatter = new BinaryFormatter();

 

  formatter.Serialize(stream, obj);

  stream.Close();

  

  // 将对象置空

  obj = null;

 

  // 打开文件"data.xml"并进行反序列化得到对象

  stream = File.Open("data.xml", FileMode.Open);

  formatter = new SoapFormatter();

  //formatter = new BinaryFormatter();

 

  obj = (TestSimpleObject)formatter.Deserialize(stream);

  stream.Close();

 

  Console.WriteLine("");

  Console.WriteLine("After deserialization the object contains: ");

  obj.Print();

 }

}

 

// 一个要被序列化的测试对象的类

[Serializable()] 

 public class TestSimpleObject {

 public int member1;

 public string member2;

 public string member3;

 public double member4;

 

 // 标记该字段为不可被序列化的

[NonSerialized()] public string member5; 

 

public TestSimpleObject() {

 member1 = 11;

 member2 = "hello";

 member3 = "hello";

 member4 = 3.14159265;

 member5 = "hello world!";

}

 

public void Print() {

 Console.WriteLine("member1 = ‘{0}‘", member1);

 Console.WriteLine("member2 = ‘{0}‘", member2);

 Console.WriteLine("member3 = ‘{0}‘", member3);

 Console.WriteLine("member4 = ‘{0}‘", member4);

 Console.WriteLine("member5 = ‘{0}‘", member5);

}

}

   三.基本序列化(Basic Serialization) vs 自定义序列化(Custom Serialization):

 

  .Net框架为我们提供了两种方式的序列化:一种为基本序列化、另一种为自定义序列化。值得注意的是,序列化的方式和前面提到的序列化的格式是不同的概念。序列化的方式是指.Net框架将程序的数据转化为能被存储并传输的格式的实际过程,它是不管程序员运用了何种类型的格式器的(二进制格式器还是XML格式器)。而序列化的格式则指程序的数据是被转化成二进制格式了还是被转化成XML格式了。

 

  完成序列化的最简单的方法便是让.Net框架自动为我们完成整个过程,而我们不必去管它内部是如何具体实现的,这种方法便是前面提到的"基本序列化"。在这种方式下,我们需要做的仅仅是将类标记上[Serializable()]属性。然后.Net框架便调用该类的对象并将它转化为所需的格式。同时你还可以控制其中的某些字段不被序列化,方法就是前面所述的将该字段标记上[NonSerialized()]属性。这样,最最简单和基本的序列化工作就完成了,不过其内部是如何实现的你是不得而知的,同时你也不能进一步控制序列化过程的程序行为。

 

  如果你要获得对序列化的更大的控制权,那么你就得使用"自定义序列化"的方式。通过使用这种方式,你可以完全的控制类的哪些部分能被序列化而哪些部分不能,同时你还可以控制如何具体的进行序列化。运用该方式的好处就是能克服基本序列化所会遇到的问题。我们在运用基本序列化将一个类的对象序列化完毕并存储在文件中后,假设该对象原来有三个字段,如果此时该对象增加了一个字段,那么再将该对象从文件中反序列化出来时会发生字段数不一致的错误。这样的问题是基本序列化所不能解决的,只能运用自定义序列化的方式来解决。

 

  在介绍自定义序列化之前,我先给出介绍过程中所要用到的实例程序的代码。这是一个时间安排程序,其中要用到将不同的时间格式进行转化的操作。所以运用序列化的机制能很好的解决这个问题。

 

 

using System;

using System.Runtime.Serialization;

 

namespace SerializationSample {

[Serializable()]

 public class Schedule {

  protected System.DateTime start;

  protected System.DateTime end;

  // 每个时间间隔所要增加的毫秒数

  protected long interval;

 

  public System.DateTime Start {get{return start;}set{start=value;}}

  public System.DateTime End {get{return end;}set{end=value;}}

  public long Interval {get{return interval;}set{interval=value;}}

  public Schedule(System.DateTime Start, System.DateTime End, long Interval) {

   start=Start;

   end=End;

  interval=Interval;

}

 

// 如果已经到了结束的时间,则返回结束时间,否则返回下一次运行的时间

public System.DateTime NextRunTime {

 get {

  System.TimeSpan ts = new System.TimeSpan(end.Ticks-System.DateTime.Now.Ticks);

  if(ts.Milliseconds>0) {

   return System.DateTime.Now.AddMilliseconds(interval);

  } else {

   return end;

  }

 }

}

}

}

  自定义序列化:

 

  下面我就向大家介绍自定义序列化以及反序列化的具体过程。首先,程序的类必须实现System.Runtime.Serialization.ISerializable接口,该接口的功能就是允许对象控制其自己的序列化和反序列化过程。所以我们得重新定义上面的类:

 

 

[Serializable()]

public class ScheduleCustom : System.Runtime.Serialization.Iserializable 

 

  接下来,我们必须对该接口调用GetObjectData()的实现,也即我们必须在上面的类中给出GetObjectData()的具体实现。其函数原型如下:

 

 

void GetObjectData(SerializationInfo info, StreamingContext context); 

 

  上面的类中GetObjectData()的具体实现如下:

 

 

public void GetObjectData(SerializationInfo info,StreamingContext context) {

// 运用info对象来添加你所需要序列化的项

info.AddValue("start", start);

info.AddValue("end", end);

info.AddValue("interval", interval);

 

   然而对于这么一个简单的方法,读者可能不能理会到系列化带来的强大功能,所以下面我就给这个方法添加一些东西。如果在系列化过程中我们要查看类型为DateTime的"start"属性的输出的话,其结果会是.Net框架默认的格式:

 

  2002-12-19T14:09:13.3457440-07:00

 

  而对于没有.Net框架的用户,或是在其他时间区域内的用户而言,这么一个格式的时间可能是非常难以理解的,所以我们有必要将时间的格式转化为格林威治标准时间格式,于是修改GetObjectData()方法如下:

 

 

public void GetObjectData(SerializationInfo info,StreamingContext context) {

// 运用info对象来添加你所需要序列化的项

// 同时,将"start"和"end"属性的时间格式转化为格林威治标准时间格式

info.AddValue("start", System.TimeZone.CurrentTimeZone.ToUniversalTime(start));

info.AddValue("end", System.TimeZone.CurrentTimeZone.ToUniversalTime(end));

info.AddValue("interval", interval);

info.AddValue("timeformat", "utc");

 

  这样一来,我们在系列化过程中查看"start"属性时就会得到如下结果:

 

   8/19/2002 9:09:13 PM

 

  同时请注意我们在GetObjectData()方法中添加的一个名为"timeformat"的额外属性,通过它我们可以方便的知道系列化过程中所使用的时间格式。如果有兴趣的话,你还可以从System.Globalization.DateTimeFormatInfo这个名字空间中获取更多有关时间格式的信息。

 

  自定义反序列化:

 

  你可以通过调用一个自定义的构造函数来完成自定义反序列化的操作。该构造函数的定义如下:

 

 

public ScheduleCustom (SerializationInfo info,StreamingContext context); 

 

  在上面的类中,我们的ScheduleCustom()方法将完成把时间格式从格林威治标准时间格式反序列化为当地时间的格式的操作,其函数实现如下:

 

 

public ScheduleCustom (SerializationInfo info,StreamingContext context) {

 this.start = info.GetDateTime("start").ToLocalTime();

 this.end = info.GetDateTime("end").ToLocalTime();

 this.interval = info.GetInt32("interval");

 

  在完成自定义序列化和自定义反序列化后,我们的时间安排程序变成了如下形式:

 

 

using System;

using System.Runtime.Serialization;

 

namespace SerializationSample {

[Serializable()]

 public class ScheduleCustom : System.Runtime.Serialization.ISerializable {

 protected System.DateTime start;

 protected System.DateTime end;

 // 每个时间间隔所要增加的毫秒数

 protected long interval;

 

 public System.DateTime Start {get{return start;}set{start=value;}}

 public System.DateTime End {get{return end;}set{end=value;}}

 public long Interval {get{return interval;}set{interval=value;}}

 

 public ScheduleCustom(System.DateTime Start, System.DateTime End, long Interval) {

  start=Start;

  end=End;

  interval=Interval;

 }

 

// 如果已经到了结束的时间,则返回结束时间,否则返回下一次运行的时间

public System.DateTime NextRunTime {

 get {

  System.TimeSpan ts = new System.TimeSpan(end.Ticks-System.DateTime.Now.Ticks);

  if(ts.Milliseconds>0) {

   return System.DateTime.Now.AddMilliseconds(interval);

  } else {

   return end;

  }

 }

}

 

public void GetObjectData(SerializationInfo info,StreamingContext context) {

 // 运用info对象来添加你所需要序列化的项

 // 同时,将"start"和"end"属性的时间格式转化为格林威治标准时间格式

 info.AddValue("start", System.TimeZone.CurrentTimeZone.ToUniversalTime(start));

 info.AddValue("end", System.TimeZone.CurrentTimeZone.ToUniversalTime(end));

 info.AddValue("interval", interval);

 info.AddValue("timeformat", "utc");

}

 

public ScheduleCustom (SerializationInfo info,StreamingContext context) {

 this.start = info.GetDateTime("start").ToLocalTime();

 this.end = info.GetDateTime("end").ToLocalTime();

 this.interval = info.GetInt32("interval");

 }

}

}

 

 

  四.总结:

 

  本文向大家介绍了.Net框架下系列化机制的一些基本概念和基本的运用方法,读者在读完本文后,应该对以下几个概念有个初步了解:二进制系列化、XML系列化、基本序列化和自定义系列化,并应能够完成一些基本的系列化应用。最后,希望大家能合理有效的运用系列化机制并发挥它的功效以更好地满足实际工作需要。

 

 

----------

    序列化又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。
    .NET框架提供了两种串行化的方式:1、是使用BinaryFormatter进行串行化;2、使用SoapFormatter进行串行化;3、使用XmlSerializer进行串行化。第一种方式提供了一个简单的二进制数据流以及某些附加的类型信息,而第二种将数据流格式化为XML存储;第三种其实和第二种差不多也是XML的格式存储,只不过比第二种的XML格式要简化很多(去掉了SOAP特有的额外信息)。
    可以使用[Serializable]属性将类标志为可序列化的。如果某个类的元素不想被序列化,1、2可以使用[NonSerialized]属性来标志,2、可以使用[XmlIgnore]来标志。
    1、使用BinaryFormatter进行串行化
    下面是一个可串行化的类:
    
技术分享using System;
技术分享using System.Data;
技术分享using System.Configuration;
技术分享using System.Web;
技术分享using System.Web.Security;
技术分享using System.Web.UI;
技术分享using System.Web.UI.WebControls;
技术分享using System.Web.UI.WebControls.WebParts;
技术分享using System.Web.UI.HtmlControls;
技术分享using System.IO;
技术分享using
 System.Runtime.Serialization.Formatters.Binary;
技术分享/// <summary>
技术分享/// ClassToSerialize 的摘要说明
技术分享/// </summary>
技术分享[Serializable]
技术分享public class ClassToSerialize
技术分享{
技术分享    public int id = 100;
技术分享    public string name = "Name";
技术分享    [NonSerialized]
技术分享    public string Sex = "男";
技术分享}
技术分享

    下面是串行化和反串行化的方法:
    
技术分享public void SerializeNow()
技术分享    {
技术分享        ClassToSerialize c = new ClassToSerialize();
技术分享        FileStream fileStream = new FileStream("c:\\temp.dat", FileMode.Create);
技术分享        BinaryFormatter b = new BinaryFormatter();
技术分享        b.Serialize(fileStream, c);
技术分享        fileStream.Close();
技术分享    }
技术分享    public void DeSerializeNow()
技术分享    {
技术分享        ClassToSerialize c = new ClassToSerialize();
技术分享        c.Sex = "kkkk";
技术分享        FileStream fileStream = new FileStream("c:\\temp.dat", FileMode.Open, FileAccess.Read, FileShare.Read);
技术分享        BinaryFormatter b = new BinaryFormatter();
技术分享        c = b.Deserialize(fileStream) as ClassToSerialize;
          Response.Write(c.name);
技术分享        Response.Write(c.Sex);
技术分享        fileStream.Close();
技术分享    }

    调用上述两个方法就可以看到串行化的结果:Sex属性因为被标志为[NonSerialized],故其值总是为null。
    2、使用SoapFormatter进行串行化
    和BinaryFormatter类似,我们只需要做一下简单修改即可:
    a.将using语句中的.Formatter.Binary改为.Formatter.Soap;
    b.将所有的BinaryFormatter替换为SoapFormatter.
    c.确保报存文件的扩展名为.xml
    经过上面简单改动,即可实现SoapFormatter的串行化,这时候产生的文件就是一个xml格式的文件。
    3、使用XmlSerializer进行串行化
    关于格式化器还有一个问题,假设我们需要XML,但是不想要SOAP特有的额外信息,那么我们应该怎么办呢?有两中方案:要么编写一个实现IFormatter接口的类,采用的方式类似于SoapFormatter类,但是没有你不需要的信息;要么使用库类XmlSerializer,这个类不使用Serializable属性,但是它提供了类似的功能。
    如果我们不想使用主流的串行化机制,而想使用XmlSeralizer进行串行化我们需要做一下修改:
    a.添加System.Xml.Serialization命名空间。
    b.Serializable和NoSerialized属性将被忽略,而是使用XmlIgnore属性,它的行为与NoSerialized类似。
    c.XmlSeralizer要求类有个默认的构造器,这个条件可能已经满足了。
    下面看示例:
    要序列化的类:
    
技术分享using System;
技术分享using System.Data;
技术分享using System.Configuration;
技术分享using System.Web;
技术分享using System.Web.Security;
技术分享using System.Web.UI;
技术分享using System.Web.UI.WebControls;
技术分享using System.Web.UI.WebControls.WebParts;
技术分享using System.Web.UI.HtmlControls;
技术分享using System.Xml.Serialization;
技术分享[Serializable]
技术分享public class Person
技术分享{
技术分享    private string name;
技术分享    public string Name
技术分享    {
技术分享        get
技术分享        {
技术分享            return name;
技术分享        }
技术分享        set
技术分享        {
技术分享            name = value;
技术分享        }
技术分享    }
技术分享
技术分享
技术分享    public string Sex;
技术分享    public int Age = 31;
技术分享    public Course[] Courses;
技术分享
技术分享    public Person()
技术分享    {
技术分享    }
技术分享    public Person(string Name)
技术分享    {
技术分享        name = Name;
技术分享        Sex = "男";
技术分享    }
技术分享}
技术分享[Serializable]
技术分享public class Course
技术分享{
技术分享    public string Name;
技术分享    [XmlIgnore]
技术分享    public string Description;
技术分享    public Course()
技术分享    {
技术分享    }
技术分享    public Course(string name, string description)
技术分享    {
技术分享        Name = name;
技术分享        Description = description;
技术分享    }
技术分享}  
技术分享

    序列化和反序列化方法:
技术分享public void XMLSerialize()
技术分享    {
技术分享        Person c = new Person("cyj");
技术分享        c.Courses = new Course[2];
技术分享        c.Courses[0] = new Course("英语", "交流工具");
技术分享        c.Courses[1] = new Course("数学","自然科学");
技术分享        XmlSerializer xs = new XmlSerializer(typeof(Person));
技术分享        Stream stream = new FileStream("c:\\cyj.XML",FileMode.Create,FileAccess.Write,FileShare.Read);
技术分享        xs.Serialize(stream,c);
技术分享        stream.Close();
技术分享    }
技术分享    public void XMLDeserialize()
技术分享    {
技术分享        XmlSerializer xs = new XmlSerializer(typeof(Person));
技术分享        Stream stream = new FileStream("C:\\cyj.XML",FileMode.Open,FileAccess.Read,FileShare.Read);
技术分享        Person p = xs.Deserialize(stream) as Person;
技术分享        Response.Write(p.Name);
技术分享        Response.Write(p.Age.ToString());
技术分享        Response.Write(p.Courses[0].Name);
技术分享        Response.Write(p.Courses[0].Description);
技术分享        Response.Write(p.Courses[1].Name);
技术分享        Response.Write(p.Courses[1].Description);
技术分享        stream.Close();
技术分享    }

这里Course类的Description属性值将始终为null,生成的xml文档中也没有该节点,如下图:
技术分享<?xml version="1.0"?>
技术分享<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
技术分享  <Sex>男</Sex>
技术分享  <Age>31</Age>
技术分享  <Courses>
技术分享    <Course>
技术分享      <Name>英语</Name>
技术分享      <Description>交流工具</Description>
技术分享    </Course>
技术分享    <Course>
技术分享      <Name>数学</Name>
技术分享      <Description>自然科学</Description>
技术分享    </Course>
技术分享  </Courses>
技术分享  <Name>cyj</Name>
技术分享</Person>

    4、自定义序列化
    如果你希望让用户对类进行串行化,但是对数据流的组织方式不完全满意,那么可以通过在自定义类中实现接口来自定义串行化行为。这个接口只有一个方法,GetObjectData. 这个方法用于将对类对象进行串行化所需要的数据填进SerializationInfo对象。你使用的格式化器将构造SerializationInfo对象,然后在串行化时调用GetObjectData. 如果类的父类也实现了ISerializable,那么应该调用GetObjectData的父类实现。
    如果你实现了ISerializable,那么还必须提供一个具有特定原型的构造器,这个构造器的参数列表必须与GetObjectData相同。这个构造器应该被声明为私有的或受保护的,以防止粗心的开发人员直接使用它。
    示例如下:
    实现ISerializable的类:
    
技术分享using System;
技术分享using System.Data;
技术分享using System.Configuration;
技术分享using System.Web;
技术分享using System.Web.Security;
技术分享using System.Web.UI;
技术分享using System.Web.UI.WebControls;
技术分享using System.Web.UI.WebControls.WebParts;
技术分享using System.Web.UI.HtmlControls;
技术分享using System.Runtime.Serialization;
技术分享using System.Runtime.Serialization.Formatters.Binary;
技术分享/// <summary>
技术分享/// Employee 的摘要说明
技术分享/// </summary>
技术分享[Serializable]
技术分享public class Employee:ISerializable
技术分享{
技术分享    public int EmpId=100;
技术分享    public string EmpName="刘德华";
技术分享    [NonSerialized]
技术分享    public string NoSerialString = "NoSerialString-Test";
技术分享    public Employee()
技术分享    {
技术分享        //
技术分享        // TODO: 在此处添加构造函数逻辑
技术分享        //
技术分享    }
技术分享    private Employee(SerializationInfo info, StreamingContext ctxt)
技术分享    {
技术分享        EmpId = (int)info.GetValue("EmployeeId", typeof(int));
技术分享        EmpName = (String)info.GetValue("EmployeeName",typeof(string));
技术分享        //NoSerialString = (String)info.GetValue("EmployeeString",typeof(string));
技术分享    }
技术分享    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
技术分享    {
技术分享        info.AddValue("EmployeeId", EmpId);
技术分享        info.AddValue("EmployeeName", EmpName);
技术分享        //info.AddValue("EmployeeString", NoSerialString);
技术分享    }
技术分享}
技术分享

    序列化和反序列化方法:
技术分享public void OtherEmployeeClassTest()
技术分享    {
技术分享        Employee mp = new Employee();
技术分享        mp.EmpId = 10;
技术分享        mp.EmpName = "邱枫";
技术分享        mp.NoSerialString = "你好呀";
技术分享        Stream steam = File.Open("c:\\temp3.dat", FileMode.Create);
技术分享        BinaryFormatter bf = new BinaryFormatter();
技术分享        Response.Write("Writing Employee Info:");
技术分享        bf.Serialize(steam,mp);
技术分享        steam.Close();
技术分享        mp = null;
技术分享        //反序列化
技术分享        Stream steam2 = File.Open("c:\\temp3.dat", FileMode.Open);
技术分享        BinaryFormatter bf2 = new BinaryFormatter();
技术分享        Response.Write("Reading Employee Info:");
技术分享        Employee mp2 = (Employee)bf2.Deserialize(steam2);
技术分享        steam2.Close();
技术分享        Response.Write(mp2.EmpId);
技术分享        Response.Write(mp2.EmpName);
技术分享        Response.Write(mp2.NoSerialString);
技术分享    }

PS:本文章属个人学习总结,部分内容参考互联网上的相关文章。 其中如果发现个人总结有不正确的认知或遗漏的地方请评论告知,欢迎交流。

-----------------

序列化是将一个对象转换成字节流以达到将其长期保存在内存、数据库或文件中的处理过程。它的主要目的是保存对象的状态以便以后需要的时候使用。与其相反的过程叫做反序列化。 

序列化一个对象 

为了序列化一个对象,我们需要一个被序列化的对象,一个容纳被序列化了的对象的(字节)流和一个格式化器。进行序列化之前我们先看看System.Runtime.Serialization名字空间。ISerializable接口允许我们使任何类成为可序列化的类。 

如果我们给自己写的类标识[Serializable]特性,我们就能将这些类序列化。除非类的成员标记了[NonSerializable],序列化会将类中的所有成员都序列化。 

序列化的类型

  • 二进制(流)序列化
  • SOAP序列化
  • XML序列化
技术分享
晴风晓月
翻译于 4年前
2人顶
 翻译得不错哦!
 

二进制(流)序列化:

二进制(流)序列化是一种将数据写到输出流,以使它能够用来自动重构成相应对象的机制。二进制,其名字就暗示它的必要信息是保存在存储介质上,而这些必要信息要求创建一个对象的精确的二进制副本。在二进制(流)序列化中,整个对象的状态都被保存起来,而XML序列化只有部分数据被保存起来。为了使用序列化,我们需要引入System.Runtime.Serialization.Formatters.Binary名字空间. 下面的代码使用BinaryFormatter类序列化.NET中的string类型的对象。 

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

namespace SerializationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //Serialization of String Object          
            string strobj = "test string for serialization";
            FileStream stream = new FileStream("C:\\StrObj.txt", FileMode.Create, FileAccess.Write ,
            FileShare.None);
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, strobj);
            stream.Close();

            //Deserialization of String Object
            FileStream readstream = new FileStream("C:\\StrObj.txt", FileMode.Open , FileAccess.Read ,
            FileShare.Read );
            string readdata = (string)formatter.Deserialize(readstream);
            readstream.Close();
            Console.WriteLine(readdata);
            Console.ReadLine();

        }
    }
}
技术分享
晴风晓月
翻译于 4年前
1人顶
 翻译得不错哦!
 

SOAP序列化:

SOAP协议是一个在异构的应用程序之间进行信息交互的理想的选择。我们需要在应用程序中添加System.Runtime.Serialization.Formatters.Soap名字空间以便在.Net中使用SOAP序列化。SOAP序列化的主要优势在于可移植性。SoapFormatter把对象序列化成SOAP消息或解析SOAP消息并重构被序列化的对象。下面的代码在.Net中使用SoapFormatter类序列化string类的对象。 

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

namespace SerializationTest
 {
    class Program
    {
        static void Main(string[] args)
        {
            //Serialization of String Object            
            string strobj = "test string for serialization";
            FileStream stream = new FileStream("C:\\StrObj.txt", FileMode.Create, FileAccess.Write ,
            FileShare.None);
            SoapFormatter formatter = new SoapFormatter();
            formatter.Serialize(stream, strobj);
            stream.Close();
            //Deserialization of String Object
            FileStream readstream = new FileStream("C:\\StrObj.txt", FileMode.Open , FileAccess.Read ,
            FileShare.Read );
            string readdata = (string)formatter.Deserialize(readstream);
            readstream.Close();
            Console.WriteLine(readdata);
            Console.ReadLine();
        }
    }
}
技术分享
晴风晓月
翻译于 4年前
1人顶
 翻译得不错哦!
 

XML序列化:

根据MSDN的描述,“XML序列化将一个对象或参数的公开字段和属性以及方法的返回值转换(序列化)成遵循XSD文档标准的XML流。因为XML是一个开放的标准,XML能被任何需要的程序处理,而不管在什么平台下,因此XML序列化被用到带有公开的属性和字段的强类型类中,它的这些发生和字段被转换成序列化的格式(在这里是XML)存储或传输。” 

我们必须添加System.XML.Serialization引用以使用XML序列化。使用XML序列化的基础是XmlSerializer。下面的代码是在.Net中使用XmlSerializer类序列化string对象。 

using System;
using System.IO;
using System.Xml.Serialization;


namespace SerializationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //Serialization of String Object            
            string strobj = "test string for serialization";
            FileStream stream = new FileStream("C:\\StrObj.txt", FileMode.Create, FileAccess.Write ,
            FileShare.None);
            XmlSerializer  xmlserializer = new XmlSerializer(typeof(string));
            xmlserializer.Serialize(stream, strobj);
            stream.Close();


            //Deserialization of String Object
            FileStream readstream = new FileStream("C:\\StrObj.txt", FileMode.Open , FileAccess.Read ,
            FileShare.Read );
            string readdata = (string)xmlserializer.Deserialize(readstream);
            readstream.Close();
            Console.WriteLine(readdata);
            Console.ReadLine();


        }
    }
}
技术分享
晴风晓月
翻译于 4年前
1人顶
 翻译得不错哦!
 

什么是格式化器?

一个格式化器用来确定一个对象的序列格式。它们目的是在网络上传输一个对象之前将其序列化成合适的格式。它们提供IFormatter接口。在.NET里提供了两个格式化类:BinaryFormatter和SoapFormatter,它们都继承了IFormatter接口。 

使用序列化

序列化允许开发人员保存一个对象的状态并在需要的时候重构对象,同时很好地支持对象存储和数据交换。通过序列化,开发人员可以利用Web Service发送对象到远端应用程序,从一个域传输对象到另一个域,以XML的格式传输一个对象并能通过防火墙,或者在应用程序间保持安全性或用户特定信息等等

 

C# 序列化和反序列化

标签:body   包含   value   key   graph   nfa   exce   out   nose   

原文地址:http://www.cnblogs.com/liangqihui/p/6848148.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!