XmlSerializer - 将对象保存到配置文件
某些时候我们希望将对象状态存储到配置文件里,籍此来调整和配置系统运行参数。尽管 FX 2.0 引入了新的配置文件操作方式(读写配置文件),但依旧不方便。其实我们完全可以借用 XML 序列化引擎和 LINQ to XML,通过在现有类型上添加相关特性来达到这个目的。
1. 添加特性
下面的代码一目了然,无须多做解释。
注: XmlSerialzer 不支持 IDictionary。
2. 序列化, 反序列化
注意 XmlSerializer.Serialize 会调用 XmlWriter.WriteStartDocument(),如果我们用下面的方式会导致异常。
异常信息
3. 测试
输出:
config.xml
------------------------------------
1. 添加特性
下面的代码一目了然,无须多做解释。
public enum Sex
{
[XmlEnum("女")]
Female,
[XmlEnum("男")]
Male
}
[XmlRoot("类名")]
public class MyClass
{
private List<int> list = new List<int>();
private Dictionary<string, int> dict = new Dictionary<string, int>();
[XmlAttribute("别名")]
public string Name { get; set; }
[XmlElement("属性")]
public int X { get; set; }
[XmlArray("数组")]
[XmlArrayItem("元素")]
public string[] S { get; set; }
[XmlElement("枚举")]
public Sex Sex { get; set; }
[XmlArray("列表")]
[XmlArrayItem("列表项")]
public List<int> List { get { return list; } }
[XmlIgnore]
public Dictionary<string, int> Dict { get { return dict; } }
}
{
[XmlEnum("女")]
Female,
[XmlEnum("男")]
Male
}
[XmlRoot("类名")]
public class MyClass
{
private List<int> list = new List<int>();
private Dictionary<string, int> dict = new Dictionary<string, int>();
[XmlAttribute("别名")]
public string Name { get; set; }
[XmlElement("属性")]
public int X { get; set; }
[XmlArray("数组")]
[XmlArrayItem("元素")]
public string[] S { get; set; }
[XmlElement("枚举")]
public Sex Sex { get; set; }
[XmlArray("列表")]
[XmlArrayItem("列表项")]
public List<int> List { get { return list; } }
[XmlIgnore]
public Dictionary<string, int> Dict { get { return dict; } }
}
注: XmlSerialzer 不支持 IDictionary。
2. 序列化, 反序列化
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
static XElement Serialize(Type type, object o)
{
var serialzer = new XmlSerializer(type);
var xml = new XDocument();
using (var writer = xml.CreateWriter())
{
serialzer.Serialize(writer, o);
}
return xml.Root;
}
static T Deserialize<T>(XElement e)
{
var serialzer = new XmlSerializer(typeof(T));
using (var reader = e.CreateReader())
{
return (T)serialzer.Deserialize(reader);
}
}
using System.Xml.Linq;
using System.Xml.Serialization;
static XElement Serialize(Type type, object o)
{
var serialzer = new XmlSerializer(type);
var xml = new XDocument();
using (var writer = xml.CreateWriter())
{
serialzer.Serialize(writer, o);
}
return xml.Root;
}
static T Deserialize<T>(XElement e)
{
var serialzer = new XmlSerializer(typeof(T));
using (var reader = e.CreateReader())
{
return (T)serialzer.Deserialize(reader);
}
}
注意 XmlSerializer.Serialize 会调用 XmlWriter.WriteStartDocument(),如果我们用下面的方式会导致异常。
static XElement Serialize(XElement e, Type type, object o)
{
var serialzer = new XmlSerializer(type);
using (var writer = e.CreateWriter())
{
serialzer.Serialize(writer, o);
}
return e.Elements().SingleOrDefault();
}
static void Main(string[] args)
{
var o = new MyClass();
var xml = new XDocument(new XElement("config"));
var element = Serialize(xml.Element("config"), typeof(MyClass), o);
}
{
var serialzer = new XmlSerializer(type);
using (var writer = e.CreateWriter())
{
serialzer.Serialize(writer, o);
}
return e.Elements().SingleOrDefault();
}
static void Main(string[] args)
{
var o = new MyClass();
var xml = new XDocument(new XElement("config"));
var element = Serialize(xml.Element("config"), typeof(MyClass), o);
}
异常信息
System.InvalidOperationException was unhandled
Message="生成 XML 文档时出错。"
Source="System.Xml"
StackTrace:
在 System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, ...)
InnerException: System.InvalidOperationException
Message="无法在使用 ConformanceLevel.Fragment 创建的编写器上调用 WriteStartDocument。"
Source="System.Xml"
StackTrace:
在 System.Xml.XmlWellFormedWriter.WriteStartDocumentImpl(XmlStandalone standalone)
在 System.Xml.XmlWellFormedWriter.WriteStartDocument()
在 System.Xml.Serialization.XmlSerializationWriter.WriteStartDocument()
Message="生成 XML 文档时出错。"
Source="System.Xml"
StackTrace:
在 System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, ...)
InnerException: System.InvalidOperationException
Message="无法在使用 ConformanceLevel.Fragment 创建的编写器上调用 WriteStartDocument。"
Source="System.Xml"
StackTrace:
在 System.Xml.XmlWellFormedWriter.WriteStartDocumentImpl(XmlStandalone standalone)
在 System.Xml.XmlWellFormedWriter.WriteStartDocument()
在 System.Xml.Serialization.XmlSerializationWriter.WriteStartDocument()
3. 测试
static void Main(string[] args)
{
var o = new MyClass
{
Name = "张三",
X = 13,
S = new[] { "a", "b", "c" },
};
o.List.AddRange(new[] { 1, 2, 3, 4 });
// ---------------
var xml = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("config")
);
var element = Serialize(typeof(MyClass), o);
xml.Element("config").Add(element);
xml.Save("config.xml");
// ----------------------
var xml2 = XDocument.Load("config.xml");
var element2 = xml2.Element("config").Element("类名");
var o2 = Deserialize<MyClass>(element2);
}
{
var o = new MyClass
{
Name = "张三",
X = 13,
S = new[] { "a", "b", "c" },
};
o.List.AddRange(new[] { 1, 2, 3, 4 });
// ---------------
var xml = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("config")
);
var element = Serialize(typeof(MyClass), o);
xml.Element("config").Add(element);
xml.Save("config.xml");
// ----------------------
var xml2 = XDocument.Load("config.xml");
var element2 = xml2.Element("config").Element("类名");
var o2 = Deserialize<MyClass>(element2);
}
输出:
config.xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<config>
<类名 别名="张三" xmlns:xsi="..." xmlns:xsd="...">
<属性>13</属性>
<数组>
<元素>a</元素>
<元素>b</元素>
<元素>c</元素>
</数组>
<枚举>女</枚举>
<列表>
<列表项>1</列表项>
<列表项>2</列表项>
<列表项>3</列表项>
<列表项>4</列表项>
</列表>
</类名>
</config>
<config>
<类名 别名="张三" xmlns:xsi="..." xmlns:xsd="...">
<属性>13</属性>
<数组>
<元素>a</元素>
<元素>b</元素>
<元素>c</元素>
</数组>
<枚举>女</枚举>
<列表>
<列表项>1</列表项>
<列表项>2</列表项>
<列表项>3</列表项>
<列表项>4</列表项>
</列表>
</类名>
</config>
------------------------------------