使用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. Theano1.1-安装

    之前一直想弄theano,可是python不是很懂,在学习了一段时间之后开始安装theano.当然官网上的安装资料是全,可是也太繁琐了.这里介绍的是最简单,最方面的安装theano的方法.官网首页:h ...

  2. <实训|第八天>超级管理员管理linux用户行为权限附监控主机状态

    作为运维工程师,系统管理员,你最大的权力就是给别人分配权力,而且你还能时时控制着他们,今天就给大家介绍一下关于管理用户这一方面的前前后后.  开班第八天: 主要课程大纲:(下面我将把自己的身份定位成一 ...

  3. AngularJS中实现无限级联动菜单

    多级联动菜单是常见的前端组件,比如省份-城市联动.高校-学院-专业联动等等.场景虽然常见,但仔细分析起来要实现一个通用的无限分级联动菜单却不一定像想象的那么简单.比如,我们需要考虑子菜单的加载是同步的 ...

  4. .net程序员转行做手游开发经历(二)

    上篇主要介绍自己个人的经历,这篇主要讲下学习新语言的过程. 上次说到最终选择的语言是swift,框架用spritekit,上次有网友对为什么选择用这俩呢,为什么不用cocos和unity呢,cocos ...

  5. 用js转换joson返回数据库的时间格式为/Date(*************)/

    原理是取中间的毫秒数,再转换成js的Date类型 function ChangeDateFormat(val) { if (val != null) { var date = new Date(par ...

  6. 编程中的offsetof

    linux和windows平台都已经定义了offsetof函数,用于取struct类型中某个变量的偏移量 在stddef.h头文件中,该宏的完整说明如下: #ifdef __cplusplus #if ...

  7. 《深入理解Spark:核心思想与源码分析》(前言及第1章)

    自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...

  8. MATLAB实现频数直方图——hist的使用

      "hist" is short for "Histogram(直方图.柱状图)". 1.N = hist(Y) bins the elements of Y ...

  9. 来个linq to js

    说这个话题之前,我们来讲一下C#的linq  语法.在C#里面我们会对列表进行操作,如OrderBy(p=>p.property),Where(p=>p.property==..) 括号里 ...

  10. C++成员变量的初始化顺序问题

    问题来源: 由于面试题中,考官出了一道简单的程序输出结果值的题:如下, class A { private: int n1; int n2; public: A():n2(0),n1(n2+2){} ...