XmlSerializer - 将对象保存到配置文件

某些时候我们希望将对象状态存储到配置文件里,籍此来调整和配置系统运行参数。尽管 FX 2.0 引入了新的配置文件操作方式(读写配置文件),但依旧不方便。其实我们完全可以借用 XML 序列化引擎和 LINQ to 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; } }
}

注: 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);
  }
}

注意 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);
}

异常信息
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()

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);
}

输出:

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>

------------------------------------
posted @ 2010-01-23 23:28  RicoRui  阅读(1139)  评论(0编辑  收藏  举报