C# 序列化

本文示例完整代码
最近在操作Xml用常规的方法比较繁琐,用LinQ to xml比较简单,但我想说的是另外一种方法:自定义序列化
平时程序在操作将数据存入xml中,无非就是将复杂对象的属性保存到xml中,然后在有需要的时候再加载。使用xml序列化要using System.Xml.Serialization;请看如下:
1.普通对象的序列化

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace SerializationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Test1 t = new Test1(){ Name="li",Age=890, IsChecked=true};
            FileStream fs_create=new FileStream("t.txt",FileMode.Create,FileAccess.ReadWrite);
            XmlSerializer s = new XmlSerializer(typeof(Test1));
            s.Serialize(fs_create, t);
            fs_create.Close();
            Console.WriteLine("完成");
            Console.Read();
        }
    }
    [Serializable]
    public class Test1
    {
        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private int age;

        public int Age
        {
            get { return age; }
            set { age = value; }
        }
        private bool isChecked;

        public bool IsChecked
        {
            get { return isChecked; }
            set { isChecked = value; }
        }
    }
}

运行,查看t.txt的内容:

<?xml version="1.0"?>
<Test1 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Name>li</Name>
  <Age>890</Age>
  <IsChecked>true</IsChecked>
</Test1>

2.自定义序列化
我们可不可以把类序列化后得到这样的xml呢?

<?xml version="1.0"?>
<Test1 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Instance>
  <Name value="li"></Name>
  <Age value="890"></Age>
  <IsChecked value="true"></IsChecked>
  </Instance>
</Test1>

想达到这样的效果,就必须自定义序列化,实现IXmlSerializable接口,请看如下的实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Reflection;
using System.Xml;

namespace SerializationTest
{
    class Class1
    {
        static void Main(string[] args)
        {
            //序列化
            Test2 t = new Test2() { Name = "li", Age = 890, IsChecked = true };
            FileStream fs_create = new FileStream("t2.txt", FileMode.Create, FileAccess.ReadWrite);
            XmlSerializer s = new XmlSerializer(typeof(Test2));
            s.Serialize(fs_create, t);
            fs_create.Close();


            //反序列化
            FileStream fs_read = new FileStream("t2.txt", FileMode.Open, FileAccess.ReadWrite);
            Test2 instance = s.Deserialize(fs_read) as Test2;
            Console.WriteLine(instance);
            //Console.WriteLine("完成");
            Console.Read();
        }
    }
    public class Test2 : IXmlSerializable
    {
        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private int age;

        public int Age
        {
            get { return age; }
            set { age = value; }
        }
        private bool isChecked;

        public bool IsChecked
        {
            get { return isChecked; }
            set { isChecked = value; }
        }
        //实现IXmlSerializable接口
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }
        //实现IXmlSerializable接口,DeSerialize方法的具体实现
        public void ReadXml(System.Xml.XmlReader reader)
        {
            reader.Read();
            reader.ReadStartElement("Instance");
            while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
            {
                string proValue = reader.GetAttribute("value");
                string proName = reader.Name;//读取属性名称                                 
                Type proType = this.GetType().GetProperty(proName).PropertyType;
                object obj = System.ComponentModel.TypeDescriptor.GetConverter(proType).ConvertFrom(proValue);//将字符串值转换为属性值(属性值得类型不知)
                this.GetType().GetProperty(proName).SetValue(this, obj, null);               
                reader.Read();
            }
            reader.ReadEndElement();
            reader.ReadEndElement();
        }
        //实现IXmlSerializable接口,Serialize方法的具体实现
        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteStartElement("Instance");
                foreach (PropertyInfo proInfo in this.GetType().GetProperties())
                {
                    string proName = proInfo.Name;
                    string proValue = proInfo.GetValue(this, null).ToString();
                    writer.WriteStartElement(proName);//开始写属性名称的element
                    writer.WriteAttributeString("value", proValue);//写attribute
                    writer.WriteEndElement();//结束element;
                }
            writer.WriteEndElement(); //结束InstanceElement
        }
        public override string ToString()
        {
            string s = "";
            foreach (PropertyInfo info in this.GetType().GetProperties())
            {
                string proName = info.Name;
                string proValue = info.GetValue(this, null).ToString();
                s += string.Format("{0}:{1}\r\n",proName,proValue);
            }
            return s;
        }
    }
}

3.自定义字典和复杂对象的序列化
上述对Test2类做了自定义序列化,有时候复杂的对象类型是这样的:
一个对象里面有一个字典,字典里面的key是string,字典的Value是Test2对象的集合。如何将这个复杂的对象序列化,然后又还原呢?
字典本身是不支持序列化的,这是我们就又要实现IXmlSerializable,对字典进行处理,代码如下:

 public class MyDictionary : Dictionary<string,List<Test2>>, IXmlSerializable
    {

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            XmlSerializer s = new XmlSerializer(typeof(List<Test2>));
            reader.Read();
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                string key = reader.GetAttribute("key");
                reader.Read();
                reader.ReadStartElement("Value");
                this[key] = s.Deserialize(reader) as List<Test2>;
                reader.ReadEndElement();
                reader.ReadEndElement();
            }
            reader.ReadEndElement();
        }

        public void WriteXml(XmlWriter writer)
        {
            XmlSerializer s=new XmlSerializer(typeof(List<Test2>));
            foreach (string key in this.Keys)
            {
                writer.WriteStartElement("Dic");
                writer.WriteAttributeString("key",key);
                     writer.WriteStartElement("Value");
                     s.Serialize(writer, this[key]);
                     writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
        public override string ToString()
        {
            string s = "";
            foreach (string key in this.Keys)
            {
                s += "key:" + key+"\r\n";
                foreach(var i in this[key])
                {
                    s += i.ToString();
                }
                s += "\r\n";
            }
            return s;
        }
    }

然后再来一个类,聚合MyDictionary:

[Serializable]
public class Test3
{
    private MyDictionary dic;
    public MyDictionary Dic
    {
        get { return dic; }
        set { dic = value; }
    }
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    public override string ToString()
    {
        string s = "";
        foreach (PropertyInfo info in this.GetType().GetProperties())
        {
            //if(this.GetType().GetProperty(info.Name).GetType().Equals(typeof(MyDictionary)))
            s += string.Format("\r\n属性名:{0},值{1}\r\n", info.Name, this.GetType().GetProperty(info.Name).GetValue(this, null).ToString());
        }
        return s;
    }
}

注意:Test3类要序列化,除了类的各个属性要能被序列化外,还要求有 [Serializable]标记,如果没有这个标记,则会出错,如果一个类直接实现了IXmlSerializable接口,则不需要[Serializable]标记可实现序列化。
在Main函数中测试Test3序列化:

 Test3 t3 = new Test3()
            {
                Name = "12345678",
                Dic = new MyDictionary()
            };
            t3.Dic.Add("abc", new List<Test2>()
                {
                    new Test2(){ Age=1, Name="fjdjf",IsChecked=false},
                    new Test2(){Age=2,Name="abcdefgh",IsChecked=true},
                    new Test2{Age=3,Name="009987876",IsChecked=true}
                });
             t3.Dic.Add("efg", new List<Test2>()
                {
                    new Test2(){ Age=4, Name="fjfffdjf",IsChecked=false},
                    new Test2(){Age=5,Name="abcdfsdfsdefgh",IsChecked=true},
                    new Test2{Age=6,Name="00998fsdfsdfds7876",IsChecked=true}
                });
             XmlSerializer t3_serialize = new XmlSerializer(typeof(Test3));
             FileStream t3_fsCreate = new FileStream("t3.xml", FileMode.Create, FileAccess.ReadWrite);
             t3_serialize.Serialize(t3_fsCreate, t3);
             t3_fsCreate.Close();

             FileStream t3_fsRead = new FileStream("t3.xml", FileMode.Open, FileAccess.ReadWrite);
             Test3 tt3= t3_serialize.Deserialize(t3_fsRead) as Test3;
             t3_fsRead.Close();
             Console.WriteLine(tt3);

             Console.WriteLine("完成");
             Console.Read();

生成的t3.xml的文件内容如下:

<?xml version="1.0"?>
<Test3 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Dic>
    <Dic key="abc">
      <Value>
        <ArrayOfTest2>
          <Test2>
            <Instance>
              <Name value="fjdjf" />
              <Age value="1" />
              <IsChecked value="False" />
            </Instance>
          </Test2>
          <Test2>
            <Instance>
              <Name value="abcdefgh" />
              <Age value="2" />
              <IsChecked value="True" />
            </Instance>
          </Test2>
          <Test2>
            <Instance>
              <Name value="009987876" />
              <Age value="3" />
              <IsChecked value="True" />
            </Instance>
          </Test2>
        </ArrayOfTest2>
      </Value>
    </Dic>
    <Dic key="efg">
      <Value>
        <ArrayOfTest2>
          <Test2>
            <Instance>
              <Name value="fjfffdjf" />
              <Age value="4" />
              <IsChecked value="False" />
            </Instance>
          </Test2>
          <Test2>
            <Instance>
              <Name value="abcdfsdfsdefgh" />
              <Age value="5" />
              <IsChecked value="True" />
            </Instance>
          </Test2>
          <Test2>
            <Instance>
              <Name value="00998fsdfsdfds7876" />
              <Age value="6" />
              <IsChecked value="True" />
            </Instance>
          </Test2>
        </ArrayOfTest2>
      </Value>
    </Dic>
  </Dic>
  <Name>12345678</Name>
</Test3>

其实还可以改进,将Element减少,属性值全部存放到Attibute上,便于阅读。以后再实现。。。
本文示例完整代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值