C# Xml序列化与反序列化

Xml文本的序列化与反序列化:

    public static class XmlSerializeHelper
    {
        // 序列化:对象 -> Xml文本
        public static string SerializeToXmlString(object obj)
        {
            StringBuilder buffer = new StringBuilder();
            using (TextWriter writer = new StringWriter(buffer))
            {
                XmlSerializer xmlSrlzer = new XmlSerializer(obj.GetType());
                xmlSrlzer.Serialize(writer, obj);
            }
            return buffer.ToString();
        }

        // 反序列化:Xml文本 -> 对象
        public static TClass DeserializeFromXmlString<TClass>(string xml)
        {
            TClass obj;
            using (StringReader reader = new StringReader(xml))
            {
                XmlSerializer xmlSrlzer = new XmlSerializer(typeof(TClass));
                obj = (TClass)xmlSrlzer.Deserialize(reader);
            }
            return obj;
        }

        // 序列化:对象 -> Xml文件
        public static void SerializeToXmlFile(object obj, string file)
        {
            using(TextWriter writer = new StreamWriter(file))
            {
                XmlSerializer serializer = new XmlSerializer(obj.GetType());
                serializer.Serialize(writer, obj);
            }
        }

        // 反序列化:Xml文本 -> 对象
        public static TClass DeserializeFromXmlFile<TClass>(string file)
        {
            TClass obj;
            using (FileStream reader = new FileStream(file, FileMode.Open))
            {
                XmlSerializer xmlSrlzer = new XmlSerializer(typeof(TClass));
                obj = (TClass)xmlSrlzer.Deserialize(reader);
            }
            return obj;
        }
    }

空对象序列化后的文本:

<?xml version="1.0" encoding="utf-16"?>
<MyClassName xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />

根节点名:

  根节点名“MyClassName”就是类名,反序列化时,根节点名必须与类名一致。

  可以通过XmlRootAttribute自定义根节点名,反序列化时,根节点名必须与自定义的跟节点名一致。

无参构造函数:

  序列化时,不会调用无参构造函数,但如果没有无参构造函数,序列化报异常。

  反序列化时,会首先调用无参构造函数构造对象,然后反序列化属性值。

  无参构造函数设成private无影响。

字段与属性:

  public的字段与属性都会被序列化,private的字段和属性不会被序列化。

  基本类型:<Field>value</Field>                        Field:字段或属性名,Value是ToString()的返回值。

  List<string>:<StringList><string>s1</string><string>s2</string></StringList>     StringList:字段或属性名

  List<int>:<IntList><int>1</int><int>2</int></IntList>               IntList:字段或属性名

  嵌套对象:<SubObj><addr>1</addr><value>2</value></SubObj>

对象List:

  <SubObjList>
    <SubClass>
      <addr>1</addr>
      <value>1</value>
    </SubClass>
    <SubClass>
      <addr>2</addr>
      <value>2</value>
    </SubClass>
  </SubObjList>

泛型对象List:

  <GenericList>
    <GenericClassOfInt32String>      <!-- GenericClass<T1, T2> -->
      <val1>1</val1>
      <val2>b</val2>
    </GenericClassOfInt32String>
    <GenericClassOfInt32String>
      <val1>2</val1>
      <val2>d</val2>
    </GenericClassOfInt32String>
  </GenericList>

   Array和List的序列化文本是一样的。

   反序列化时,XML中没有的字段保留初始化值,XML中多出的字段直接忽略,不会报异常。

类继承:

   类型与对象相同:对XML序列化无影响,能访问的属性或字段就能序列化与反序列化。

  使用基类属性保存派生类对象,需要在基类上添加[XmlInclude(typeof(ExtendClass))],序列化后的XML文本中会多出 xsi:type="ExtendClass"。

  接口不能序列化。

    [XmlInclude(typeof(ExtendClass1))]
    [XmlInclude(typeof(ExtendClass2))]
    public class BaseClass
    {
        public int BP { get; set; }
    }
    public class ExtendClass1 : BaseClass
    {
        public int EP1 { get; set; }
    }
    public class ExtendClass2 : BaseClass
    {
        public int EP2 { get; set; }
    }
    public class MyClassName
    {
        public List<BaseClass> ObjList{ get; set; }
    }
<?xml version="1.0" encoding="utf-8"?>
<MyClassName xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ObjList>
    <BaseClass xsi:type="ExtendClass1">
      <BP>1</BP>
      <EP1>11</EP1>
    </BaseClass>
    <BaseClass xsi:type="ExtendClass2">
      <BP>2</BP>
      <EP2>22</EP2>
    </BaseClass>
  </ObjList>
</MyClassName>

Dictionary:

  不能序列化,可以使用SerializableDictionary(网上有现成的)。

[DefaultValue(true)]:

  属性上加了该Attribute之后,如果值与DefaultValue相同,XML中不会生成节点,反序列化时却不会设置成DefaultValue,需要在构造函数里通过反射来设置DefaultValue。

去除xmlns:xsd:

                StringBuilder buffer = new StringBuilder();
                using (TextWriter writer = new StringWriter(buffer))
                {
                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add("", "");
                    XmlSerializer xmlSrlzer = new XmlSerializer(obj.GetType());
                    xmlSrlzer.Serialize(writer, obj, ns);
                }

[XmlAttribute]实现XML属性:

    public class SubClass
    {
        [XmlAttribute]
        public int ID { get; set; }

        public string Name { get; set; }
   }
    public class MyClassName
    {
        [XmlAttribute]
        public int Type { get; set; }

        public int Num { get; set; }

        public SubClass Sub { get; set; }
    }
<?xml version="1.0" encoding="utf-16"?>
<MyClassName Type="0">
  <Num>100</Num>
  <Sub ID="1">
    <Name>HAHA</Name>
  </Sub>
</MyClassName>