使用XmlSerializer可以方便的将对象序列化为xml,实现应用之间的数据交互。但是XmlSerializer却不能很好地序列化类型中的可空字段。 
例如,有如下定义的类Person:

  1. [Serializable]
  2. [XmlRoot(ElementName = "Person")]
  3. public class Person
  4. {
  5. public string FirstName { get; set; }
  6. public string LastName { get; set; }
  7. public int? Age { get; set; }
  8. }

其中的Age属性为Nullable int类型。 
我们的实例化代码如下所示:

  1. var person = new Person
  2. {
  3. FirstName = "First",
  4. };
  5. person.OutputXml(Console.Out);

其中方法OutputXml为扩展方法,使用XmlSerializer来序列化对象,具体定义为:

  1. public static void OutputXml<T>(this T dto, TextWriter textWriter)
  2. {
  3. var xmlTypeMapping = typeof(T);
  4. var serializer = new XmlSerializer(xmlTypeMapping);
  5. var xmlns = new XmlSerializerNamespaces();
  6. xmlns.Add(string.Empty, string.Empty);
  7. using (var writer = new XmlTextWriter(textWriter) { Formatting = Formatting.Indented })
  8. {
  9. serializer.Serialize(writer, dto, xmlns);
  10. }
  11. }

使用上述方法序列化对象person,得到的结果为: 
 
注意到虽然Age属性为空,却仍然被序列化成 了古怪的xml,这往往不是所期望的结果。事实上同为空的LastName属性的序列化正是大多数情况下我们所期望的行为——忽略为空的属性。 
另一方面,如果试图序列化类属性为xml 属性(而非xml元素),则甚至不能工作。例如如果我们将Person类的定义修改成如下形式以便序列化为xml属性:

  1. [Serializable]
  2. [XmlRoot(ElementName = "Person")]
  3. public class Person
  4. {
  5. [XmlAttribute]
  6. public string FirstName { get; set; }
  7. [XmlAttribute]
  8. public string LastName { get; set; }
  9. [XmlAttribute]
  10. public int? Age { get; set; }
  11. }

Xmlserializer甚至无法正常序列化上面同样的person对象并抛出如下“XmlAttribute/XmlText cannot be used to encode complex types”的错误: 
 
如何解决上述的2个问题呢? 
1. 序列化可空属性为XmlElement 
为了在序列化可空属性的时候忽略空值的古怪输出,我们可以在Person类中定义一个返回bool的特殊方法ShouldSerializeAge,并在其中实现定义我们的序列化规则:

  1. [Serializable]
  2. [XmlRoot(ElementName = "Person")]
  3. public class Person
  4. {
  5. public string FirstName { get; set; }
  6. public string LastName { get; set; }
  7. public int? Age { get; set; }
  8. public bool ShouldSerializeAge()
  9. {
  10. return Age.HasValue;
  11. }
  12. }

在这里我们定义序列化规则为:序列化非空Age。注意该方法的名字一定是以ShouldSerialize开头并连接上需要自定义规则的属性名称。这样序列化出来的person对象为: 
 
空的Age和空的LastName一样在序列化时被忽略了输出。正是我们期望的结果! 
2. 序列化可空属性为XmlAttribute 
由于可空属性无法被直接序列化为XmlAttribute,我们需要采用间接的办法——定义间接属性。此时我们可以如下定义Person类:

  1. [Serializable]
  2. [XmlRoot(ElementName = "Person")]
  3. public class Person
  4. {
  5. [XmlAttribute]
  6. public string FirstName { get; set; }
  7. [XmlAttribute]
  8. public string LastName { get; set; }
  9. [XmlIgnore]   // (4)
  10. public int? Age { get; set; }
  11. [XmlAttribute(AttributeName = "Age")]  // (1)
  12. public string AgeValue
  13. {
  14. get
  15. {
  16. // (2)
  17. return Age.HasValue ? Age.Value.ToString() : null;
  18. }
  19. set
  20. {
  21. int result;
  22. // (3)
  23. Age = int.TryParse(value, out result) ? result : (int?) null;
  24. }
  25. }
  26. }

注意类中注释的部分:

  1. 为原可空属性定义一个“虚拟”的属性,该属性可为任意名称任意类型(示例里定义的为string类型的AgeValue),但注意要将该属性的序列化名称置为原可空属性Age。
  2. 在get方法里根据Age是否为空将其转化为AgeValue。
  3. 在set方法里将输入的value转化为合适的值赋给可空属性Age。
  4. 将原Age属性标记为XmlIgnore,使XmlSerializer在序列化时忽略序列化该属性。

使用上述方法,我们可以将Age序列化为XmlAttribute了,虽然实际上我们是“骗”了XmlSerializer并使用另一个属性作为Age属性的值。 
因此,当person对象中的Age为空时,我们得到如下的xml结果: 
 
而当person对象中的Age不为空时,我们也可以正常的用XmlAttribute来表示Age的值了。 

使用XmlSerializer序列化可空属性的更多相关文章

  1. XmlSerializer序列化

    XmlSerializer在命名空间using System.Xml.Serialization下. 序列化和反序列化的代码: using System.IO; using System.Xml; u ...

  2. C#.NET如何不序列化字段、属性

    当我们使用公开属性以及公开字段时,都可以顺利的被序列化, 01.[Serializable] 02.public class MyClass 03.{ 04.    public int ID; 05 ...

  3. .NET调用外部接口将得到的List数据,并使用XmlSerializer序列化List对象成XML格式

    BidOpeningData.BidSupervisionSoapClient client = new BidOpeningData.BidSupervisionSoapClient(); Dict ...

  4. 第一章 JacksonUtil 序列化与反序列化属性总结

    1.json-lib与Jackson 关于json-lib与Jackson对比总结如下: 1).性能方面,Jackson的处理能力高出Json-lib10倍左右. 2).json-lib已经停止更新, ...

  5. c# XML序列化与反序列化 属性字段标识

    序列化对象 public class People { [XmlAttribute("NAME")] public string Name { set; get; } [XmlAt ...

  6. 学习C# XmlSerializer 序列化反序列化XML

    类.变量常用头: [XmlRootAttribute]:对根节点的描述,在类声明中使用 如:下例的Html类 [XmlType]:对节点描述,在类声明中使用         如:下例的Head类 [X ...

  7. C# XmlSerializer序列化浅析

    C# 中使用 XmlSerializer 实现类和xml文件的序列化和反序列化,使用起来非常简单. C# XmlSerializer实现序列化: XmlSerializer xml = new Xml ...

  8. C#调用XmlSerializer序列化时生成CDATA节点解决方法

    public class Person{    public string Name { get; set; }    public int Age { get; set; }        } 引用 ...

  9. js如何判断Object是否为空?(属性是否为空)

    js 判断一个 object 对象是否为空 转载原文 判断一个对象是否为空对象,本文给出三种判断方法: 1.最常见的思路,for...in... 遍历属性,为真则为“非空数组”:否则为“空数组” fo ...

随机推荐

  1. 让时间处理简单化 【第三方扩展类库org.apache.commons.lang.time】

    JAVA的时间日期处理一直是一个比较复杂的问题,大多数程序员都不能很轻松的来处理这些问题.首先Java中关于时间的类,从 JDK 1.1 开始,Date的作用很有限,相应的功能已由Calendar与D ...

  2. Bootstrap系列 -- 44. 分页导航

    带页码的分页导航,可能是最常见的一种分页导航,特别是在列表页内容超多的时候,会给用户提供分页的导航方式.平时很多同学喜欢用div>a和div>span结构来制作带页码的分页导航.不过,在B ...

  3. Common Issues Which Cause Roles to Recycle

    This section lists some of the common causes of deployment problems, and offers troubleshooting tips ...

  4. ASP.NET Web API 实现客户端Basic(基本)认证 之简单实现

    优点是逻辑简单明了.设置简单. 缺点显而易见,即使是BASE64后也是可见的明文,很容易被破解.非法利用,使用HTTPS是一个解决方案. 还有就是HTTP是无状态的,同一客户端每次都需要验证. 实现: ...

  5. mysql 定义自增

    The database returned no natively generated identity value问题 alter table user_table MODIFY user_id I ...

  6. Linux中TFTP使用详解

    FTP协议简介TFTP是用来下载远程文件的最简单网络协议,它其于UDP协议而实现. linux服务器端tftp-server的配置1.安装tftp服务器需要安装xinetd(守护tftp).tftp和 ...

  7. 【前端积累】createElement createTextNode

    <!DOCTYPE html> <html><!--树根--> <head> <meta charset="utf-8"> ...

  8. [转]Hibernate与Jpa的关系,终于弄懂

    原文地址:http://blog.sina.com.cn/s/blog_5f1619e80100yoxz.html 我知道Jpa是一种规范,而Hibernate是它的一种实现.除了Hibernate, ...

  9. Servlet作业1-实现注册登录

    1,注册功能 注册页面zhuce.html <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" &q ...

  10. 【CodeVS 3289】【NOIP 2013】花匠

    http://codevs.cn/problem/3289/ dp转移,树状数组维护前缀max和后缀max进行优化,$O(nlogn)$. #include<cstdio> #includ ...