C#三十一 序列化与反序列化

举报
tea_year 发表于 2021/12/30 01:37:35 2021/12/30
【摘要】 序列化又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。    .NET框架提供了两种串行化的方式:1、是使用BinaryFormatter进行串行化;2、使用SoapFormatter进行串行化;...

序列化又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。
    .NET框架提供了两种串行化的方式:1、是使用BinaryFormatter进行串行化;2、使用SoapFormatter进行串行化;3、使用XmlSerializer进行串行化。第一种方式提供了一个简单的二进制数据流以及某些附加的类型信息,而第二种将数据流格式化为XML存储;第三种其实和第二种差不多也是XML的格式存储,只不过比第二种的XML格式要简化很多(去掉了SOAP特有的额外信息)。
    可以使用[Serializable]属性将类标志为可序列化的。如果某个类的元素不想被序列化,1、2可以使用[NonSerialized]属性来标志,2、可以使用[XmlIgnore]来标志。

 视频课堂https://edu.csdn.net/course/play/7621

 

重点:

Ø      理解序列化 / 反序列化概念

Ø      能够使用序列化/反序列化保持和恢复对象状态

 

 

预习功课:

Ø      序列化的概念

Ø      反序列化的概念

Ø      如何使用序列化和反序列化保持和恢复对象状态

Ø      如何利用序列化来操作Xml文件

 

 

 

8.1 序列化和反序列化简介

C#序列化和反序列化,两者的程序处理方式基本一致,都是基于工厂模式的,所谓C#序列化就是是将对象转换为容易传输的格式的过程,一般情况下转化打流文件,放入内存或者IO文件中。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象,或者和其它应用程序共享使用。相反的,反序列化根据流重新构造对象。.NET自带的有两种序列化对象的方式,Xml和binary的,XML 序列化不转换方法、索引器、私有字段或只读属性(只读集合除外)。要序列化对象的所有字段和属性(公共的和私有的),请使用 BinaryFormatter,而不要使用 XML 序列化。

8.1.1 C#序列化和反序列化的实例应用剖析:

二进制的C#序列化的方式:

例如我们有个对象:

1.            [Serializable]public class ClassToSerialize{ 

2.            public int id=100; 

3.            public string name="Name";  

4.            }  

需要序列化该对象,必须在给该类加上Serializable的属性,然后创建一个序列化写入的流:FileStream fileStream = new FileStream("temp.dat",FileMode.Create);然后创建二进制格式器:BinaryFormatter b=newBinaryFormatter();然后是序列化:b.Serialize(fileStream,c);,然后关闭保存流。(可以见下面的例子)

读取一个已经被序列化的对象的时候:操作方式一样,只是

5.           FileStream fileStream = new FileStream(  

6.           "temp.dat", FileMode.Open,  

7.           FileAccess.Read, FileShare.Read);  

8.           ClassToSerialize c =  

9.           (ClassToSerialize)b.Deserialize(fileStream); 

然后就可以读取了,完整的例子是:

10.       using System;  

11.       using System.IO;  

12.       using System.Runtime.Serialization;  

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

14.       public class SerialTest{  

15.       public void SerializeNow(){  

16.       ClassToSerialize c=new ClassToSerialize();  

17.       FileStream fileStream = new FileStream(  

18.       "temp.dat", FileMode.Create); 

19.        

20.       BinaryFormatter b=new BinaryFormatter();  

21.       b.Serialize(fileStream,c);  

22.       fileStream.Close();  

23.       }  

24.       public void DeSerializeNow(){  

25.       ClassToSerialize c=new ClassToSerialize();  

26.       FileStream fileStream = new FileStream(  

27.       "temp.dat", FileMode.Open, 

28.        FileAccess.Read,  

29.        FileShare.Read);  

30.       BinaryFormatter b=new BinaryFormatter();  

31.       //SoapFormatter 

32.       c=(ClassToSerialize)b.Deserialize(fileStream);  

33.       Console.WriteLine(c.name);  

34.       fileStream.Close();  

35.       }  

36.       public static void Main(string[] s){  

37.       SerialTest st=new SerialTest();  

38.       st.SerializeNow();  

39.       st.DeSerializeNow();  

40.       }  

41.       }  

42.       [Serializable]  

43.       public class ClassToSerialize{  

44.       public int id=100;  

45.       public string name="Name";  

46.       }  

这就是自带的序列化和反序列的操作,但是,很多情况下,一个对象比较大,而且很多私有的属性和方法我们不需要,例如在原型模式里面序列化的话,只需要序列Clone方法和一些属性,私有的方法无需要,还例如在读取大规模的IO的时候,读取操作完全不需要... 这时候就需要自己集成重写序列的ISerializable接口:

实现该接口需要两个注意的,一个就是构造函数,主要是为了反序列,另一个就是GetObjectData,主要是执行序列化,例如我们现在有一个Employee类需要序列化

47.       [Serializable()]  

48.       //Set this attribute to all the classes that want to serialize 

49.       public class Employee : ISerializable   

50.       //derive your class from ISerializable { 

51.       public int EmpId;  

52.       public string EmpName;  

53.       [NonSerialized()]  

54.       public string NoSerialString="NoSerialString-Test";  

55.        

56.       } 

需要注意的是我这里的NoSerialString属性前面有[NonSerialized()],就是说默认并不序列化这个属性,而是使用默认值。

首先是构造函数:

57.       public Employee(SerializationInfo info, StreamingContext ctxt) 

58.       {  

59.       EmpId = (int)info.GetValue(  

60.       "EmployeeId"typeof(int));  

61.       EmpName = (String)info.GetValue(  

62.       "EmployeeName"typeof(string));  

63.       //NoSerialString =  

64.       //(String)info.GetValue("NoSerialString", typeof(string)); 

65.       } 

然后是C#序列化方法,就是当写入流的时候怎么保存的:

66.       public void GetObjectData(SerializationInfo info, StreamingContext ctxt) {  

67.        

68.       info.AddValue("EmployeeId", EmpId);  

69.       info.AddValue("EmployeeName", EmpName);  

70.       } 

把上面两个方法写入到Employee类,然后写个测试的程序:

71.       public class ObjSerial{  

72.       public static void Main(String[] args){  

73.       Employee mp = new Employee();  

74.       mp.EmpId = 10;  

75.       mp.EmpName = "Omkumar";  

76.       mp.NoSerialString = "你好啊";  

77.        

78.          //C#序列化和反序列化之序列化 

79.       Stream stream = File.Open("EmployeeInfo.osl", FileMode.Create); 

80.       BinaryFormatter bformatter = new BinaryFormatter(); 

81.        

82.       Console.WriteLine("Writing Employee Information");  

83.       bformatter.Serialize(stream, mp);  

84.       stream.Close();  

85.        

86.        

87.       mp = null;  

88.          //C#序列化和反序列化之反序列 

89.       stream = File.Open("EmployeeInfo.osl", FileMode.Open); 

90.       bformatter = new BinaryFormatter();  

91.        

92.       Console.WriteLine("Reading Employee Information");  

93.       mp = (Employee)bformatter.Deserialize(stream);  

94.       stream.Close();  

95.        

96.       Console.WriteLine(  

97.       "Employee Id: {0}",mp.EmpId.ToString()); 

98.       Console.WriteLine(  

99.       "Employee Name: {0}",mp.EmpName);  

100.     Console.WriteLine( 

101.     "Employee NoSerialString: {0}",mp.NoSerialString); 

102.      

103.     }  

104.     }  

C#序列化和反序列化程序执行的结果是:

105.     Writing Employee Information 

106.     Reading Employee Information 

107.     Employee Id: 10 

108.     Employee Name: Omkumar 

109.     Employee NoSerialString: NoSerialString-Test 

看到Employee NoSerialString:属性的值没有,它保持默认值,没有序列化。

 

 

8.2 Xml格式序列化及反序列化

 

要序列化的对象的类:
  [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;
  }
  }
  进行序列化及反序列化的测试类:
  class Test
  {
  //序列化
  public void Serialiaze()
  {
  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 = newFileStream("c:\\cyj.xml", FileMode.Create, FileAccess.Write,FileShare.ReadWrite);
  xs.Serialize(stream, c);
  stream.Close();
  }
  //反序列化
  public void Deserialize()
  {
  XmlSerializer xs=new XmlSerializer(typeof(Person));
  Stream stream = newFileStream("c:\\cyj.xml", FileMode.Open, FileAccess.Read,FileShare.ReadWrite);
  Person p=(Person)xs.Deserialize(stream);
  Console.WriteLine(p.Name);
  Console.WriteLine(p.Age.ToString());
  Console.WriteLine(p.Courses.Length.ToString());
  Console.Read();
  }
  }
  格式化后Xml的文档内容为:
  <?xml version="1.0"?>
  <Person xmlns:xsd=http://www.w3.org/2001/XMLSchemaxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Sex>男</Sex>
   <Age>31</Age>
   <Courses>
   <Course>
      <Name>英语</Name>
   </Course>
   <Course>
      <Name>数学</Name>
   </Course>
   </Courses>
      <Name>cyj</Name>
  </Person>

文章来源: aaaedu.blog.csdn.net,作者:tea_year,版权归原作者所有,如需转载,请联系作者。

原文链接:aaaedu.blog.csdn.net/article/details/51365560

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。