赞
踩
本文示例完整代码
最近在操作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上,便于阅读。以后再实现。。。
本文示例完整代码
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。