代码改变世界

序列化与反序列化

2017-06-04 16:59  Dirichlet  阅读(302)  评论(0编辑  收藏  举报
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Globalization;

namespace SerializeSample
{
    class Program
    {
        static void Main(string[] args)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(TemplateDescription[]));
            StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);

            List<TemplateDescription> list = new List<TemplateDescription>();
            TemplateDescription template = new TemplateDescription("aaa", "bbb", 100);
            template.ObjectValue = new int[2] { 1, 2 };
            TemplateDescription template2 = new TemplateDescription("mmm", "nnn", 101);
            template2.ObjectValue = new byte[2] { 3, 4 };

            list.Add(template);
            list.Add(template2);

            // Serialize
            serializer.Serialize(writer, list.ToArray());
            File.WriteAllText(@"d:\serialize.txt", writer.ToString());
            Console.WriteLine(writer.ToString());

            // DeSerialize
            TemplateDescription[] test = (TemplateDescription[])serializer.Deserialize(new StringReader(writer.ToString()));
            Console.WriteLine(test[0].ToString());
        }
    }

    [XmlInclude(typeof(int[]))]
    public class TemplateDescription
    {
        public TemplateDescription()
        {
            this.Name = string.Empty;
            this.Description = string.Empty;
            this.ID = 0;
            this.ObjectValue = null;
        }

        public TemplateDescription(string name, string description, int id)
        {
            this.Name = name;
            this.Description = description;
            this.ID = id;
        }

        public string Name { get; set; }
        public string Description { get; set; }
        public int ID { get; set; }

        [XmlElement("Value")]
        public object ObjectValue { get; set; }

        [XmlIgnore]
        public int[] IntegerArrayValue
        {
            get { return (int[])ObjectValue; }
            set { ObjectValue = value; }
        }

        [XmlIgnore]
        public byte[] ByteArrayValue
        {
            get { return (byte[])ObjectValue; }
            set { ObjectValue = value; }
        }
    }

}
View Code

 

xml format的序列化只是针对公有属性。

1. 序列化数组,需要指定特质属性[XmlArrayItem(typeof(...))]。

如果不指定则有可能不能正确序列化,从实验看int数组不指定也可以正确序列化,byte数组就必须得指定。如下:

public class MyClass
    {
        public int[] IDs { get; set; }

        public byte[] BTs { get; set; }

        public char Charactor { get; set; }

        public MyClass()
        {
            this.IDs = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
            this.BTs = new byte[] { 121, 122, 123, 124, 255, 201 };
            this.Charactor = 'a';
        }
    }

序列化结果,BTs看上去不正确,其实是经过了based64编码的结果,是正确的。但是如果想得到显式的结果最好加上[XmlArrayItem(typeof(byte))]。

<?xml version="1.0" encoding="utf-16"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<IDs>
<int>1</int>
<int>2</int>
<int>3</int>
<int>4</int>
<int>5</int>
<int>6</int>
<int>7</int>
<int>8</int>
<int>9</int>
<int>0</int>
</IDs>
<BTs>eXp7fP/J</BTs>
<Charactor>97</Charactor>
</MyClass>

 

加上特制属性:

    public class MyClass
    {
        public int[] IDs { get; set; }

        [XmlArrayItem(typeof(byte))]
        public byte[] BTs { get; set; }

        public char Charactor { get; set; }

        public MyClass()
        {
            this.IDs = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
            this.BTs = new byte[] { 121, 122, 123, 124, 255, 201 };
            this.Charactor = 'a';
        }
    }


        static void Test5()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
            StringWriter writer = new StringWriter();
            MyClass myObject = new MyClass();

            serializer.Serialize(writer, myObject);
            Console.WriteLine(writer.ToString());
        }

序列化正确:

<?xml version="1.0" encoding="utf-16"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <IDs>
    <int>1</int>
    <int>2</int>
    <int>3</int>
    <int>4</int>
    <int>5</int>
    <int>6</int>
    <int>7</int>
    <int>8</int>
    <int>9</int>
    <int>0</int>
  </IDs>
  <BTs>
    <unsignedByte>121</unsignedByte>
    <unsignedByte>122</unsignedByte>
    <unsignedByte>123</unsignedByte>
    <unsignedByte>124</unsignedByte>
    <unsignedByte>255</unsignedByte>
    <unsignedByte>201</unsignedByte>
  </BTs>
  <Charactor>97</Charactor>
</MyClass>

 

2. 当某个需要序列化的field或者property具有不确定的类型时,如果要正确序列化它必须在类型上指定[XmlInclude(typeof(...)),XmlInclude(typeof(...))]属性,标识property可能的类型。

如下,public object ObjectValue { get; set; }属性可能是int[],byte[], 所以TemplateDescription加XmlInclude属性。

    [XmlInclude(typeof(byte[])), XmlInclude(typeof(int[]))]
    public class TemplateDescription

  Notes:

     只加[XmlInclude(typeof(int[]))]也可以正确序列化byte[]数组的情况。

        [XmlInclude(typeof(int[]))]
        public class TemplateDescription

    只不过 byte[]数组序列化为based64编码结果<Value xsi:type="xsd:base64Binary">AwQ=</Value>,请考虑序加[XmlArrayItem(typeof(byte))] 。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Xml.Serialization;
 6 using System.IO;
 7 using System.Globalization;
 8 
 9 namespace SerializeSample
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             XmlSerializer serializer = new XmlSerializer(typeof(TemplateDescription[]));
16             StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
17 
18             List<TemplateDescription> list = new List<TemplateDescription>();
19             TemplateDescription template = new TemplateDescription("aaa", "bbb", 100);
20             template.ObjectValue = new int[2] { 1, 2 };
21             TemplateDescription template2 = new TemplateDescription("mmm", "nnn", 101);
22             template2.ObjectValue = new byte[2] { 3, 4 };
23 
24             list.Add(template);
25             list.Add(template2);
26 
27             // Serialize
28             serializer.Serialize(writer, list.ToArray());
29             File.WriteAllText(@"d:\serialize.txt", writer.ToString());
30             Console.WriteLine(writer.ToString());
31 
32             // DeSerialize
33             TemplateDescription[] test = (TemplateDescription[])serializer.Deserialize(new StringReader(writer.ToString()));
34             Console.WriteLine(test[0].ToString());
35         }
36     }
37 
38     [XmlInclude(typeof(byte[])), XmlInclude(typeof(int[]))]
39     public class TemplateDescription
40     {
41         public TemplateDescription()
42         {
43             this.Name = string.Empty;
44             this.Description = string.Empty;
45             this.ID = 0;
46             this.ObjectValue = null;
47         }
48 
49         public TemplateDescription(string name, string description, int id)
50         {
51             this.Name = name;
52             this.Description = description;
53             this.ID = id;
54         }
55 
56         public string Name { get; set; }
57         public string Description { get; set; }
58         public int ID { get; set; }
59 
60         [XmlElement("Value")]
61         public object ObjectValue { get; set; }
62 
63         [XmlIgnore]
64         public int[] IntegerArrayValue
65         {
66             get { return (int[])ObjectValue; }
67             set { ObjectValue = value; }
68         }
69 
70         [XmlIgnore]
71         public byte[] ByteArrayValue
72         {
73             get { return (byte[])ObjectValue; }
74             set { ObjectValue = value; }
75         }
76     }
77 
78 }

 

 1 <?xml version="1.0" encoding="utf-16"?>
 2 <ArrayOfTemplateDescription xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 3   <TemplateDescription>
 4     <Name>aaa</Name>
 5     <Description>bbb</Description>
 6     <ID>100</ID>
 7     <Value xsi:type="ArrayOfInt">
 8       <int>1</int>
 9       <int>2</int>
10     </Value>
11   </TemplateDescription>
12   <TemplateDescription>
13     <Name>mmm</Name>
14     <Description>nnn</Description>
15     <ID>101</ID>
16     <Value xsi:type="xsd:base64Binary">AwQ=</Value>
17   </TemplateDescription>
18 </ArrayOfTemplateDescription>

 

 二.

注意:当类成员变量中出现不能被序列化的类或接口时候我们要通过

[NonSerialized]   只针对成员变量

[XmlIgnore]   针对成员变量和属性,只针对XML序列化

标记其不被序列化和反序列化

特别注意:要使某属性在XML序列化过程中不被序列化只能使用[XmlIgnore],[NonSerialized]无效

 

三.

 “上午同事问我一个问题,实体序列化时报了一个错:The type ConsoleTest.Item was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically. 分析之后,发现了问题,原来被序列化的实体其中一个Property的类型是Object,但是实例化时给这个Property赋了一个自定义的Item,因此序列化未通过。之后,在Property上加上属性[XmlElement(typeof(Item))]即可序列化成功。
       利用Xml序列化技术进行开发有一段时间了,总结了此应用的一些经验,供网友分享。”

http://blog.csdn.net/henrylubin/article/details/2047671

扩展问题:如果Object在某时刻又被赋值为其他非item对象了呢?Property上加上属性[XmlElement(typeof(Item))]还是不够彻底,最好在类上加

[XmlInclude(typeof(...)), XmlInclude(typeof(...))]

 

 

所有的Attribute Class:

http://msdn.microsoft.com/en-us/library/system.attribute.aspx#inheritanceContinued