使用XmlSerializer序列化可空属性

时间:2022-12-12 20:06:27

使用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,得到的结果为: 
使用XmlSerializer序列化可空属性 
注意到虽然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”的错误: 
使用XmlSerializer序列化可空属性 
如何解决上述的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对象为: 
使用XmlSerializer序列化可空属性 
空的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结果: 
使用XmlSerializer序列化可空属性 
而当person对象中的Age不为空时,我们也可以正常的用XmlAttribute来表示Age的值了。 
使用XmlSerializer序列化可空属性

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

  1. XmlSerializer序列化

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

  2. C&num;&period;NET如何不序列化字段、属性

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

  3. &period;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&num; XML序列化与反序列化 属性字段标识

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

  6. 学习C&num; XmlSerializer 序列化反序列化XML

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

  7. C&num; XmlSerializer序列化浅析

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

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

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

  9. js如何判断Object是否为空&quest;&lpar;属性是否为空&rpar;

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

随机推荐

  1. 设计模式初学者笔记:Factory Method模式

    如果要选择一种最多人熟悉的Factory Method模式的具体应用,那么就应该是MFC的App/Doc架构了.Factory Method主要在类框架中使用,以解决以下问题:框架必须实例化类,但框架 ...

  2. SqlServer 查看数据库锁,解除锁,此种情况一般常见都是由于事务所造成

    检查数据库锁 SELECT request_session_id spid,OBJECT_NAME(resource_associated_entity_id)tableNameFROM sys.dm ...

  3. 为什么新建的管理员账号权限没有Administrator大?

    Administrator是超级管理员,UAC不用确认,跟关了一样. 新建隶属于administrator组的用户,可以关掉UAC. 控制面板>系统和安全>操作中心>更改用户帐户控制 ...

  4. django note

    2016-2-9 Unknown command: 'syncdb'  solution: syncdb command is deprecated in django 1.7. Use the py ...

  5. 在spring MVC的controller中获取ServletConfig

    在使用SmartUpload进行文件上传时,须要用到srevletConfig: 假设是在servlet中写当然是非常easy实现的: private ServletConfig config; // ...

  6. 举例说,Linux核心名单(两)

    使用列表 我认为最好的方式,成为熟悉的核心列表功能是看一些简单的例子,素材去更好的理解链表. 以下是一个样例.包括创建.加入.删除和遍历链表. <span style="font-si ...

  7. grep之字符串搜索算法Boyer-Moore由浅入深(比KMP快3-5倍)(转)

    这篇长文历时近两天终于完成了,前两天帮网站翻译一篇文章“为什么GNU grep如此之快?”,里面提及到grep速度快的一个重要原因是使用了Boyer-Moore算法作为字符串搜索算法,兴趣之下就想了解 ...

  8. C&plus;&plus; list forward&lowbar;list

    list,forward_list list:双向链表 forward_list:单向链表 在任何位置添加元素,删除元素都很快,但随机访问元素则很慢 声明和初始化 list<T> l; l ...

  9. Dynamics CRM REST Builder

    今天介绍个很棒的工具叫CRM REST Builder,不管是2016之前的odata查询或者现在的web api都不在话下,界面如下,选项非常丰富 这里以retrieve multiple举个例子, ...

  10. &period;NetCore2&period;1 WebAPI新增Swagger插件

    说明 Swagger是一个WebAPI在线注解.调试插件,过去我们主要通过手工撰写WebAPI接口的交互文档供前端开发人员或外部开发者, 官网地址:https://swagger.io/. 但是在实际 ...