你的位置:首页 > ASP.net教程

[ASP.net教程]【转】Xml序列化


   

一、

  在本节开始之前,首先来看一个最简单的示例:

namespace 学习测试{  class Program  {    static void Main(string[] args)    {      Person p = new Person(1, "刘备", 176);      string "";      //      using (MemoryStream ms = new MemoryStream())      {        Type t = p.GetType();        = new byte[] arr = ms.ToArray();        = Encoding.UTF8.GetString(arr, 0, arr.Length);        ms.Close();      }      Console.WriteLine(public class Person  {    //必须定义一个无参数构造函数,否则无法序列化(当然完全不写构造函数也是可以序列化的,因为有个默认的无参构造函数)    public Person() { }    public Person(int id, string name, int age)    {      Id = id;      Name = name;      //Age = age;    }    public int Id { get; set; }    public string Name { get; set; }    //私有字段    private int Age { get; set; }    //只读属性    private int height;    public int Height { get { return height; } }  }}

  该代码输出如下:

  

  从以上输出,我们可以得出结论,必须要求无参构造函数,默认的也可以。但注意当默认的无参构造函数比覆盖时,要补上一个无参构造函数。另外,私有属性,只读属性是不能被序列化的。

  更多的注意事项:

  1. 要序列化的类必须有默认的构造的构造函数,才能使用
  2. 方法不能被序列化;
  3. 索引器、私有字段或只读属性(只读集合属性除外)不能被序列化;
  4. 需要序列化的类都必须有一个无参的构造函数
  5. 枚举变量可序列化为字符串,无需用[
  6. 导出非基本类型对象,都必须用[
  7. Attribute中的IsNullable参数若等于false,表示若元素为null则不显示该元素。(针对值类型有效)
  8. 某些类就是无法
  • IDictionary(如HashTable)
  • 父类对象赋予子类对象值的情况
  • 对象间循环引用

  9.对于无法

  • 使用自定义
  • 实现IDictionary的类,可考虑(1)用其它集合类替代;(2)用类封装之,并提供Add和this函数
  • 某些类型需要先经过转换,然后才能序列化为
  • 过于复杂的对象用

  不想序列化时:

  • 当不想序列化一个属性时,使用[System.
  • [NonSerializable]应用于属性无效,能用于类,结构体等

  默认构造函数是必须的,因为反序列化本质上使用的是反射,需要默认构造函数来实例化类,如果去掉其中的默认构造函数,则编译没有问题,但运行就会报错。

  尽量不要将比较大的属性放在默认构造函数初始化,那会导致在反序列化时对列表初始化两次:默认构造函数中执行一次,反序列化时从

二、改变

  通常,在

  1、去除默认的命名空间与前缀:

  new "", "");  //第一个参数是前缀,第二个参数是命名空间  //然后在序列化的时候,指定自定义命名空间  

  输出对比:

     

  当然,这个方法也可以用于生成你想要的自定义命名空间。

  2、去除

    public static string ObjectTo= new //去除      settings.Omittrue;      settings.Encoding = Encoding.Default;      System.IO.MemoryStream mem = new MemoryStream();      using ( //去除默认命名空间        new "", "");        = new return Encoding.Default.GetString(mem.ToArray());    }

  输出:

  

  3、换行缩进

  settings.Indent = true;

  当

  

  4、指定缩进字符

  settings.IndentChars = "--";

  输出如下:

  

  

成员说明
CloseOutput获取或设置一个值,该值指示在调用 Close 方法时,
Encoding获取或设置要使用的文本编码的类型。
Indent获取或设置一个值,该值指示是否缩进元素。
IndentChars获取或设置缩进时要使用的字符串。
NamespaceHandling获取或设置一个值,该值指示在编写
NewLineChars获取或设置要用于分行符的字符串
NewLineHandling获取或设置一个值,该值指示是否将输出中的分行符正常化。
NewLineOnAttributes获取或设置一个值,该值指示是否将属性写入新行。
Omit获取或设置一个值指示省略
Encoding获取或设置要使用的文本编码的类型。
Reset方法重置以上属性

      http://msdn.microsoft.com/zh-cn/library/system.

三、实现序列化接口I

  实现I

  该接口包含3个方法:

 GetSchema();void Read reader);void Write writer);

  简单示例:

namespace 自定义序列化{  class Program  {    static void Main(string[] args)    {      Person p = new Person();      p.Id = 1;      p.Name = "刘备";      string str = ObjectTo= ObjectTo(str);      Console.WriteLine("我的名字是:" + p1.Name);      Console.ReadKey();    }    //序列化    public static string ObjectTostring "";      = new //去除//settings.Omit      settings.Indent = true;      settings.Encoding = Encoding.Default;      using (System.IO.MemoryStream mem = new MemoryStream())      {        using ( //去除默认命名空间          new "", "");          = new = Encoding.Default.GetString(mem.ToArray());      }      return //反序列化    public static T ObjectTostring str)where T : class    {      object obj;      using (System.IO.MemoryStream mem = new MemoryStream(Encoding.Default.GetBytes(str)))      {        using ( = new typeof(T));          obj = formatter.Deserialize(reader);        }      }      return obj as T;    }  }  public class Person  {    public int Id { get; set; }    public string Name { get; set; }  }  public class PersonSerializer : Iprivate Person p;    public int Id { get; set; }    public string Name { get; set; }    #region I    System.throw new NotImplementedException();    }    //如果这个方法默认则报:    void I"Person");    }    void I"Id", Id.ToString());      writer.WriteElementString("Name", Name);    }    #endregion  }}

  输出如下:

  

  我们都知道,接口是不支持序列化的。下面来做个有用的示例,实现IList<T>的序列化与反序列化

namespace IList<T>的序列化与反序列化{  class Program  {    static void Main(string[] args)    {      Woman w1 = new Woman() { Id = 1, Name = "貂蝉" };      Woman w2 = new Woman() { Id = 2, Name = "西施" };      List<Woman> ListWoman = new List<Woman>();      ListWoman.Add(w1);      ListWoman.Add(w2);      Person p = new Person();      p.Id = 1;      p.Name = "刘备";      p.ListWoman = ListWoman;      string str = ObjectTo= ObjectTo(str);      Console.WriteLine("我的名字是:" + p1.Name + "我的老婆有:");      foreach (Woman w in p1.ListWoman)      {        Console.WriteLine(w.Name);      }      Console.ReadKey();    }    //序列化    public static string ObjectTostring "";      = new //去除//settings.Omit      settings.Indent = true;      settings.Encoding = Encoding.Default;      using (System.IO.MemoryStream mem = new MemoryStream())      {        using ( //去除默认命名空间          new "", "");          = new = Encoding.Default.GetString(mem.ToArray());      }      return //反序列化    public static T ObjectTostring str) where T : class    {      object obj;      using (System.IO.MemoryStream mem = new MemoryStream(Encoding.Default.GetBytes(str)))      {        using ( = new typeof(T));          obj = formatter.Deserialize(reader);        }      }      return obj as T;    }  }  public class Person : Ipublic int Id { get; set; }    public string Name { get; set; }    public IList<Woman> ListWoman { get; set; }    #region I    System.throw new NotImplementedException();    }    void I       //一定要特别注意配对问题,否则很容易反序列化集合出现只能够读取第一个的情况
reader.ReadStartElement("Person"); Id = Convert.ToInt32(reader.ReadElementString("Id")); Name = reader.ReadElementString("Name"); //我也不知道为什么,复杂类型只能够另外定义一个,获得值之后再给原来的赋值 List<Woman> ListWoman2 = new List<Woman>(); reader.ReadStartElement("ListWoman"); while (reader.IsStartElement("Woman")) { Woman w = new Woman(); reader.ReadStartElement("Woman"); w.Id = Convert.ToInt32(reader.ReadElementString("Id")); w.Name = reader.ReadElementString("Name"); reader.ReadEndElement(); reader.MoveToContent(); ListWoman2.Add(w); } ListWoman = ListWoman2; reader.ReadEndElement(); reader.ReadEndElement(); } void I       //这里是不需要WriteStart/End Person的 writer.WriteElementString("Id", Id.ToString()); writer.WriteElementString("Name", Name); //有重载,想设置命名空间,只需在参数加上 writer.WriteStartElement("ListWoman"); foreach (Woman item in ListWoman) { PropertyInfo[] ProArr = item.GetType().GetProperties(); writer.WriteStartElement("Woman"); foreach (PropertyInfo p in ProArr) { writer.WriteElementString(p.Name, p.GetValue(item, null).ToString()); } writer.WriteEndElement(); } writer.WriteEndElement(); } #endregion } public class Woman { public int Id { get; set; } public string Name { get; set; } }}

  输出如下:

  

  以上代码是能够直接用于序列化数组的,也就是IList<Person>的,下面在贴上两个序列化与反序列化IList<T>的方法:

    //序列化    public static string ListTo ListT)    {      = new = new MemoryStream();      = new = true;      settings.Omit= false;      settings.Encoding = Encoding.UTF8;      = string strtmp = Encoding.UTF8.GetString(mem.ToArray());      return strtmp;    }    //反序列化    public static List<T> (Stream stream)    {      string @"\OutLine\" + typeof(T).Name + ".";      using (StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8))      {        = new typeof(List<T>));        var listsch = ser.Deserialize(sr);        List<T> reses = listsch as List<T>;        return reses;      }    }

  下面给出一个序列化与反序列化通过反射的复杂对象的示例:

using System.Linq.Expressions;namespace 控制台___学习测试{  class Program  {    static void Main(string[] args)    {      Woman w1 = new Woman() { Id = 1, Name = "貂蝉" };      Woman w2 = new Woman() { Id = 2, Name = "西施" };      List<Woman> ListWoman1 = new List<Woman>();      ListWoman1.Add(w1);      ListWoman1.Add(w2);      List<Person> ListPerson = new List<Person>();      Person p1 = new Person() { Id = 1, Name = "刘备", ListWoman = ListWoman1 };      Person p2 = new Person() { Id = 2, Name = "关羽", ListWoman = ListWoman1 };      Person p3 = new Person() { Id = 3, Name = "张飞", ListWoman = ListWoman1 };      ListPerson.Add(p1);      ListPerson.Add(p2);      ListPerson.Add(p3);      string  ListTo= new MemoryStream(Encoding.UTF8.GetBytes(<Person> ListPerson2 = (mem);      Console.WriteLine(ListPerson2.Count);      Console.WriteLine(ListPerson2[2].ListWoman[1].Name);      Console.ReadKey();    }    //序列化    public static string ListTo ListT)    {      = new = new MemoryStream();      = new = true;      settings.Omit= true;      settings.Encoding = Encoding.UTF8;      = string strtmp = Encoding.UTF8.GetString(mem.ToArray());      File.WriteAllText(@"D:\222.", strtmp);      return strtmp;    }    //反序列化    public static List<T> (Stream stream)    {      using (StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8))      {        = new typeof(List<T>));        var listsch = ser.Deserialize(sr);        List<T> reses = listsch as List<T>;        return reses;      }    }  }  public class Person : Ipublic int Id { get; set; }    public string Name { get; set; }    public IList<Woman> ListWoman { get; set; }    #region I    System.throw new NotImplementedException();    }    void I//while (reader.Name == "Person")      //{      reader.ReadStartElement("Person");      Id = Convert.ToInt32(reader.ReadElementString("Id"));      Name = reader.ReadElementString("Name");      List<Woman> newWomans = new List<Woman>();      PropertyInfo[] ProArr = typeof(Woman).GetProperties();      reader.ReadStartElement("ListWoman");      while (reader.IsStartElement("Woman"))      {        Woman Item2 = new Woman();        reader.ReadStartElement("Woman");        foreach (PropertyInfo p in ProArr)        {          string str = reader.ReadElementString(p.Name);          p.SetValue(Item2, Convert.ChangeType(str, p.PropertyType), null);        }        reader.ReadEndElement();        reader.MoveToContent();        newWomans.Add(Item2);      }      ListWoman = newWomans;      reader.ReadEndElement();      reader.ReadEndElement();    }    void I"Id", Id.ToString());      writer.WriteElementString("Name", Name);      writer.WriteStartElement("ListWoman");      foreach (Woman item in ListWoman)      {        PropertyInfo[] ProArr = item.GetType().GetProperties();        writer.WriteStartElement("Woman");        foreach (PropertyInfo p in ProArr)        {          if (p.GetValue(item, null) != null)          {            writer.WriteElementString(p.Name, p.GetValue(item, null).ToString());          }          else          {            writer.WriteElementString(p.Name, "");          }        }        writer.WriteEndElement();      }      writer.WriteEndElement();    }    #endregion  }  public class Woman  {    public int Id { get; set; }    public string Name { get; set; }  }}

  以上代码输出:

  

  特别提示,一定要特别特别注意,ReadStartElement与ReadEndElement的问题,否则很容易出现反序列化集合时只能够读取第一个的情况。而对于序列化,如果WriteStartElement与WriteEndElement不匹配,出现的只是

四、

  有时,我们在序列化时想要自定义

名称描述
表示一个特性对象的集合,这些对象控制
指定
指定
表示
指定
指定可以通过使用枚举来进一步消除成员的歧义
表示
控制
指示
允许
控制视为
当序列化或反序列化时,想
控制当属性目标由
指定成员(返回
指定成员可以包含对象,该对象表示在序列化或反序列化的对象中没有相应成员的所有
表示
为UnKnowAttribute提供数据
允许你在使用
为UnknownElement事件提供数据
指定目标属性、参数、返回值或类成员包含与
为UnknownNode时间提供数据
将对象序列化到
包含
包含从一种类型到另一种类型的映射

  更多更详细的说明,可以在这里看到:http://msdn.microsoft.com/zh-cn/library/System.

  下面仅仅给出两个简单示例:

namespace 学习测试{  [Serializable]  public class Person  {    public Person() { }    public int Id { get; set; }    public string Name { get; set; }    [(DataType = "string")]    public string Content { get; set; }    []    public int Age { get; set; }    []    [("Int32", typeof(Int32))]    public IList ListInt { get; set; }  }  class Program  {    static void Main(string[] args)    {      IList list = new ArrayList();      list.Add(1);      list.Add(2);      list.Add(3);      Person p = new Person();      p.Id = 1;      p.Name = "刘备";      p.Age = 23;      p.Content = "这是一个牛人";      p.ListInt = list;      string str ObjectTo//反序列化IList还有问题      //Person p2 = ObjectTo//Console.WriteLine(p2.Name);      Console.ReadKey();    }    //序列化    public static string ObjectTostring "";      = new //去除//settings.Omit      settings.Indent = true;      settings.Encoding = Encoding.Default;      using (System.IO.MemoryStream mem = new MemoryStream())      {        using ( //去除默认命名空间          new "", "");          = new = Encoding.Default.GetString(mem.ToArray());      }      return //反序列化    public static T ObjectTostring str) where T : class    {      object obj;      using (System.IO.MemoryStream mem = new MemoryStream(Encoding.Default.GetBytes(str)))      {        using ( = new typeof(T));          obj = formatter.Deserialize(reader);        }      }      return obj as T;    }  }}

2013/12/27 常遇错误记录:

反序列化错误提示:

1、

  报这个错误一般是由于序列化与反序列化的类型不一致:

 @"C:\Person.",person);  //person 是 Person类的对象var test = typeof(Person), @"C:\Person.");

2014/08/12

2、

  1、NonSerialized只作用于字段。

  2、

 转自:http://www.cnblogs.com/kissdodog/archive/2013/12/10/3468385.html