zoukankan      html  css  js  c++  java
  • 序列化和反序列化的几种方式(DataContractSerializer)

    序列化和反序列化的几种方式(DataContractSerializer)

    DataContractSerializer 

         使用提供的数据协定,将类型实例序列化和反序列化为 XML 流或文档。 无法继承此类。

    命名空间: System.Runtime.Serialization
    程序集:  System.Runtime.Serialization(在 System.Runtime.Serialization.dll 中)

    备注

         使用 DataContractSerializer 类可以将类型实例序列化和反序列化为 XML 流或文档。 通过将 DataContractAttribute 特性应用于类,而将DataMemberAttribute 特性应用于类成员,可以指定要序列化的属性和字段。

          从字面意思来理解就是:数据契约序列化,本文主要是讲解用DataContractSerializer 序列化和反序列化,关于它在WCF中的应用大家可以参考《WCF全面解析上册 蒋金楠著》第五章 序列化,里面有专门的介绍。

    DataContractAttribute与DataMenmberAttribute

     DataContractAttribute

    #region 程序集 System.Runtime.Serialization.dll, v4.0.0.0
    // C:Program FilesReference AssembliesMicrosoftFramework.NETFrameworkv4.5System.Runtime.Serialization.dll
    #endregion

    using System;

    namespace System.Runtime.Serialization
    {
    // 摘要:
    // 指定该类型要定义或实现一个数据协定,并可由序列化程序(如 System.Runtime.Serialization.DataContractSerializer)进行序列化。
    // 若要使其类型可序列化,类型作者必须为其类型定义数据协定。
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)]
    public sealed class DataContractAttribute : Attribute
    {
    // 摘要:
    // 初始化 System.Runtime.Serialization.DataContractAttribute 类的新实例。
    public DataContractAttribute();

    // 摘要:
    // 获取或设置一个值,该值指示是否保留对象引用数据。
    //
    // 返回结果:
    // 如果使用标准 XML 保留对象引用数据,则为 true;否则为 false。 默认值为 false。
    public bool IsReference { get; set; }
    //
    // 摘要:
    // 获取或设置类型的数据协定的名称。
    //
    // 返回结果:
    // 数据协定的本地名称。 默认值是应用了该属性的类的名称。
    public string Name { get; set; }
    //
    // 摘要:
    // 获取或设置类型的数据协定的命名空间。
    //
    // 返回结果:
    // 协定的命名空间。
    public string Namespace { get; set; }
    }
    }

    DataContractAttribute

          从应用在DataContractAttribute上的AttributeUsageAttribute特性看,该特性只能用于枚举、类、结构体而不能应用于接口,从关键字sealed知道DataContractAttribute是不可被继承的。AllowMutiple属性为False,表明一个数据类型上只能应用一个DataContractAttribute特性。

          从上面对DataContractAttribute定义看出DataContractAttribute仅仅包含3个属性成员,其中Name和Namespace表示数据契约的名称和命名空间,IsReference表示在进行序列化的时候是否保持对象现有的引用结构,该属性默认值为False。

           数据契约成员采用显示选择机制,也就是说,应用了DataContractAttribute特性的数据类型的属性/字段不会自动生成契约的数据成员,而只有那些应用了DataMemberAttribute特性的属性/字段才属于数据契约的成员。

     DataMemberAttribute

    #region 程序集 System.Runtime.Serialization.dll, v4.0.0.0
    // C:Program FilesReference AssembliesMicrosoftFramework.NETFrameworkv4.5System.Runtime.Serialization.dll
    #endregion

    using System;

    namespace System.Runtime.Serialization
    {
    // 摘要:
    // 当应用于类型的成员时,指定该成员是数据协定的一部分并可由 System.Runtime.Serialization.DataContractSerializer
    // 进行序列化。
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
    public sealed class DataMemberAttribute : Attribute
    {
    // 摘要:
    // 初始化 System.Runtime.Serialization.DataMemberAttribute 类的新实例。
    public DataMemberAttribute();

    // 摘要:
    // 获取或设置一个值,该值指定是否对正在被序列化的字段或属性的默认值进行序列化。
    //
    // 返回结果:
    // 如果应该在序列化流中生成成员的默认值,则为 true;否则为 false。 默认值为 true。
    public bool EmitDefaultValue { get; set; }
    //
    // 摘要:
    // 获取或设置一个值,该值用于指示序列化引擎在读取或反序列化时成员必须存在。
    //
    // 返回结果:
    // 如果该成员是必需的,则为 true;否则为 false。
    //
    // 异常:
    // System.Runtime.Serialization.SerializationException:
    // 该成员不存在。
    public bool IsRequired { get; set; }
    //
    // 摘要:
    // 获取或设置数据成员名称。
    //
    // 返回结果:
    // 该数据成员的名称。 默认值是应用该属性的目标的名称。
    public string Name { get; set; }
    //
    // 摘要:
    // 获取或设置成员的序列化和反序列化的顺序。
    //
    // 返回结果:
    // 序列化或反序列化的数字顺序。
    public int Order { get; set; }
    }
    }

    DataMemberAttribute

          从上面应用在DataMemberAttribute上的AttributeUsageAttribute特性来看,该特性只能应用在字段和属性上。因为只有这两种元素才是“数据”成员。4个属性分别表示如下的含义。

    •  Name:数据成员的名称,默认为字段或属性的名称。
    •  Order:相应的数据成员在最终序列化的XML中出现的位置,Order值越小越考前,默认值为-1.
    • IsRequired:表明属性成员是否是必须的成员。默认值为false,表明该成员是可以缺省的。
    • EmitDefaultValue :获取或设置一个值,该值指定是否对正在被序列化的字段或属性的默认值进行序列化。如果应该在序列化流中生成成员的默认值,则为 true;否则为 false。 默认值为 true。

     实例:

         Person类

     Person

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Runtime.Serialization;
    namespace DataContractSerializerDemo
    {
    [DataContract]
    public class Person
    {
    public Person(string name, int age, DateTime bithday)
    {
    this.name = name;
    this.age = age;
    this.birthday = bithday;
    }
    private string name;
    [DataMember]
    public string Name
    {
    get { return name; }
    set { name = value; }
    }
    private int age;
    [DataMember]
    public int Age
    {
    get { return age; }
    set { age = value; }
    }
    private DateTime birthday;
    [DataMember]
    public DateTime Birthday
    {
    get { return birthday; }
    set { birthday = value; }
    }
    }
    }

    Person

        Women类(Person类的子类)

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Runtime.Serialization;
     7 namespace DataContractSerializerDemo
     8 {
     9     [DataContract]
    10     public class Women : Person
    11     {
    12         public Women(string name, int age, DateTime birthday, string bwh, string bra)
    13             : base(name, age, birthday)
    14         {
    15             BWH = bwh;
    16             Bra = bra;
    17         }
    18         /// <summary>
    19         /// 罩杯
    20         /// </summary>
    21         [DataMember]
    22         public string BWH { get; set; }
    23         /// <summary>
    24         /// 罩颜色
    25         /// </summary>
    26         public string Bra { get; set; }
    27     }
    28 }
    复制代码

        控制台程序:

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Runtime.Serialization;
     7 using System.Xml;
     8 namespace DataContractSerializerDemo
     9 {
    10     class Program
    11     {
    12         static void Main(string[] args)
    13         {
    14             Person p = new Person("wolfy", 24, Convert.ToDateTime("1989-04-11"));
    15             Women w = new Women("苍老师",40,Convert.ToDateTime("1960-01-01"),"D罩杯","黑色蕾丝");
    16             Serialize<Person>(p, "p.xml");
    17             Serialize<Women>(w,"w.xml");
    18             Console.Read();
    19 
    20         }
    21         /// <summary>
    22         /// 序列化辅助方法
    23         /// </summary>
    24         /// <typeparam name="T"></typeparam>
    25         /// <param name="instance"></param>
    26         /// <param name="fileName"></param>
    27         static void Serialize<T>(T instance, string fileName)
    28         {
    29             DataContractSerializer serializer = new DataContractSerializer(typeof(T));
    30             using (XmlWriter writer = new XmlTextWriter(fileName,Encoding.UTF8))
    31             {
    32                 serializer.WriteObject(writer, instance);
    33             }
    34         }
    35     }
    36 }
    复制代码

        最后生成的xml文件:p.xml

    1 <Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DataContractSerializerDemo"><Age>24</Age><Birthday>1989-04-11T00:00:00</Birthday><Name>wolfy</Name></Person>

       w.xml

    1 <Women xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DataContractSerializerDemo"><Age>40</Age><Birthday>1960-01-01T00:00:00</Birthday><Name>苍老师</Name><BWH>D罩杯</BWH></Women>

      将数据契约与最终生成的XML结构进行对比,我们可以看出DataContractSerializer在默认的情况下采用了如下的序列化规则。

    • XML的根节点名称为数据契约类型的名称(这里为Person),默认的命名空间采用的格式为 http://schemas.datacontract.org/2004/07/DataContractSerializerDemo(数据契约类型的命名空间)。
    • 只有显示地应用了DataMemberAttributue特性的字段或属性才能作为数据成员参与序列化。
    • 所有数据成员均以XML元素的形式被序列化。
    • 序列化后数据成员在XML中的次序采用这样的规则:父类数据成员在前,子类数据成员在后;定义在同一个类型中的数据成员按照字母排序。

          如果默认序列化后的xml结构不能满足我们的需求,则可以通过DataContractAttribute和DataMenmberAttribute这两个特性对其进行修正。在下面我们通过DataContractAttribute特性设置了数据契约的名称和命名空间,通过DataMenmberAttribute特性的Name属性为Name和Birthday两个属性设置不同于属性名称的数据成员名称,并通过Order控制数据成员的先后次序。

         修改后的Person类为:

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Runtime.Serialization;
     7 namespace DataContractSerializerDemo
     8 {
     9     [DataContract(Namespace="http://www.wolfy.com/")]
    10     public class Person
    11     {
    12         public Person(string name, int age, DateTime bithday)
    13         {
    14             this.name = name;
    15             this.age = age;
    16             this.birthday = bithday;
    17         }
    18         private string name;
    19         [DataMember(Name="FirstName",Order=3)]
    20         public string Name
    21         {
    22             get { return name; }
    23             set { name = value; }
    24         }
    25         private int age;
    26         [DataMember]
    27         public int Age
    28         {
    29             get { return age; }
    30             set { age = value; }
    31         }
    32         private DateTime birthday;
    33         [DataMember(Name="生日",Order=1)]
    34         public DateTime Birthday
    35         {
    36             get { return birthday; }
    37             set { birthday = value; }
    38         }
    39     }
    40 }
    复制代码

         再次运行程序,得到如下一个表示序列化的Person对象的XML结构:

    <Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.wolfy.com/"><Age>24</Age><生日>1989-04-11T00:00:00</生日><FirstName>wolfy</FirstName></Person>

         有关序列化的方方面面还有很多,这里就把经常用到介绍到这里。

         反序列化辅助方法:

    复制代码
     1  static T DeSerialize<T>(string fileName)
     2         {
     3             DataContractSerializer serializer = new DataContractSerializer(typeof(T));
     4             using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
     5             {
     6                 using (XmlReader reader = new XmlTextReader(fileName, fs))
     7                 {
     8                     return (T)serializer.ReadObject(reader);
     9                 }
    10             }
    11 
    12         }
    复制代码

         运行结果为:

          从反序列化的结果也从侧面印证了:只有显示地应用了DataMemberAttributue特性的字段或属性才能作为数据成员参与序列化。这条规则,因为在上面并没有给bra这个属性加DataMenmberAttribute这个特性,在生成的xml文件中没有这个元素。反序列化也不会出现这个。

           上篇随笔: 序列化和反序列化的几种方式(JavaScriptSerializer 、XmlSerializer、DataContractSerializer)(一)

           参考文献:

                 MSDN:http://msdn.microsoft.com/library/system.runtime.serialization.datacontractserializer.aspx

                 《WCF全面解析 上》 蒋金楠 著

     
     
    分类: C#WCF
  • 相关阅读:
    发布几个DNN模块自己写的,功能还不完善
    c#冒泡排序正解!
    74很多小学生在学习加法时,发现“进位”特别容易出错。你的任务是计算两个三位数在相加时需要多少次进位。你编制的程序应当可以连续处理多组数据,直到读到两个0(这是输入结束标记)。
    69 N!阶乘是一个非常大的数,大家都知道计算公式是N!=N*(N1)······*2*1.现在你的任务是计算出N!的位数有多少(十进制)?首行输入n,表示有多少组测试数据(n<10)随后n行每行输入一组测试数据 N( 0 < N < 1000000 )
    96已知w是一个大于10但不大于1000000的无符号整数,若w是n(n≥2)位的整数,则求出w的后n1位的数。第一行为M,表示测试数据组数。接下来M行,每行包含一个测试数据。
    101输入两点坐标(X1,Y1),(X2,Y2)(0<=x1,x2,y1,y2<=1000),计算并输出两点间的距离第一行输入一个整数n(0<n<=1000),表示有n组测试数据;随后每组占一行由4个实数组成,分别表示x1,y1,x2,y2,数据之间用空格隔开 对于每组输入数据,输出一行结果保留两位
    266 给定一行字符,逆序输出此行(空格.数字不输出)
    98描述 输入一个百分制的成绩M,将其转换成对应的等级,具体转换规则如下:90~100为A;80~89为B;70~79为C;60~69为D;0~59为E;输入 第一行是一个整数N,表示测试数据的组数(N<10)
    50爱摘苹果的小明小明家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果。苹果成熟的时候,小明就会跑去摘苹果。小明有个30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。现在已知10个苹果到地面的高度,以及小明把手伸直的时候能够达到的最大高度请帮小明算一下她能够摘到的苹果的数
    100 小南刚学了二进制,他想知道一个数的二进制表示中有多少个1,你能帮他写一个程序来完成这个任务吗?
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3321975.html
Copyright © 2011-2022 走看看