`
zz8ss5ww6
  • 浏览: 64379 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

使用XmlSerializer序列化可空属性

阅读更多
使用XmlSerializer可以方便的将对象序列化为xml,实现应用之间的数据交互。但是XmlSerializer却不能很好地序列化类型中的可空字段。
例如,有如下定义的类Person:
    [Serializable]
    [XmlRoot(ElementName = "Person")]
    public class Person
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public int? Age { get; set; }
    }

其中的Age属性为Nullable int类型。
我们的实例化代码如下所示:
            var person = new Person
                             {
                                 FirstName = "First",
                             };
            person.OutputXml(Console.Out);

其中方法OutputXml为扩展方法,使用XmlSerializer来序列化对象,具体定义为:
public static void OutputXml<T>(this T dto, TextWriter textWriter)
{
    var xmlTypeMapping = typeof(T);
    var serializer = new XmlSerializer(xmlTypeMapping);
    var xmlns = new XmlSerializerNamespaces();
    xmlns.Add(string.Empty, string.Empty);
    using (var writer = new XmlTextWriter(textWriter) { Formatting = Formatting.Indented })
    {
        serializer.Serialize(writer, dto, xmlns);
    }
}

使用上述方法序列化对象person,得到的结果为:

注意到虽然Age属性为空,却仍然被序列化成 了古怪的xml,这往往不是所期望的结果。事实上同为空的LastName属性的序列化正是大多数情况下我们所期望的行为——忽略为空的属性。
另一方面,如果试图序列化类属性为xml 属性(而非xml元素),则甚至不能工作。例如如果我们将Person类的定义修改成如下形式以便序列化为xml属性:
    [Serializable]
    [XmlRoot(ElementName = "Person")]
    public class Person
    {
        [XmlAttribute]
        public string FirstName { get; set; }

        [XmlAttribute]
        public string LastName { get; set; }

        [XmlAttribute]
        public int? Age { get; set; }
    }

Xmlserializer甚至无法正常序列化上面同样的person对象并抛出如下“XmlAttribute/XmlText cannot be used to encode complex types”的错误:

如何解决上述的2个问题呢?
1. 序列化可空属性为XmlElement
为了在序列化可空属性的时候忽略空值的古怪输出,我们可以在Person类中定义一个返回bool的特殊方法ShouldSerializeAge,并在其中实现定义我们的序列化规则:
    [Serializable]
    [XmlRoot(ElementName = "Person")]
    public class Person
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public int? Age { get; set; }

        public bool ShouldSerializeAge()
        {
            return Age.HasValue;
        }
    }

在这里我们定义序列化规则为:序列化非空Age。注意该方法的名字一定是以ShouldSerialize开头并连接上需要自定义规则的属性名称。这样序列化出来的person对象为:

空的Age和空的LastName一样在序列化时被忽略了输出。正是我们期望的结果!
2. 序列化可空属性为XmlAttribute
由于可空属性无法被直接序列化为XmlAttribute,我们需要采用间接的办法——定义间接属性。此时我们可以如下定义Person类:
    [Serializable]
    [XmlRoot(ElementName = "Person")]
    public class Person
    {
        [XmlAttribute]
        public string FirstName { get; set; }

        [XmlAttribute]
        public string LastName { get; set; }

        [XmlIgnore]   // (4) 
        public int? Age { get; set; }

        [XmlAttribute(AttributeName = "Age")]  // (1)
        public string AgeValue
        {
            get
            {
                // (2)
                return Age.HasValue ? Age.Value.ToString() : null;
            }
            set
            {
                int result;
                // (3)
                Age = int.TryParse(value, out result) ? result : (int?) null;
            }
        }
    }

注意类中注释的部分:
  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的值了。
0
0
分享到:
评论

相关推荐

    二进制BinaryFormatter进行序列化与反序列化

    .NET框架提供了两种种串行化的方式:1、是使用BinaryFormatter进行串行化;2、使用XmlSerializer进行串行化。...如果某个类的元素不想被序列化,1、可以使用[NonSerialized]属性来标志,2、可以使用[XmlIgnore]来标志。

    XmlSerializer 常见问题疑难解答(MSDN)

    例如,元数据属性必须描述序列化程序可以处理的 XML 格式的所有变体。本文研究了在使用 XmlSerializer 构建基于 XML 的解决方案时可能发生的各种错误,并且讨论了用来诊断这些错误的技巧和工具。

    序列化Hashtable

    这样偷一下,上面的这个MyCollection类就是可以被序列化的了,然后把SortedList其他属性包一下,就基本可以当成一个SortedList使用了,说它是Hashtable也差不多吧――外表基本看不出来。不过局限性还是有喽。它的...

    .NET 高级代码审计(第一课)XmlSerializer 反序列漏洞

    员使用 Type 类的静态方法获取外界数据,并调用 Deserialize 反序列化 xml 数据就会 触发反序列化漏洞攻击(例如 DotNetNuke 任意代码执行漏洞 CVE-2017-9822),本 文笔者从原理和代码审计的视角做了相关脑图介绍和...

    C#序列化和反序列化XML代码实现

    XmlSerializer类 多级节点、属性指定说明

    XmlSerializer基本例子以及注意事项(代码注释)

    3. 对于枚举类型的属性,在序列化之前一定要赋值,否则会序列化失败。这个问题我在Windows service程序下调试了半天,才发现。奇怪怎么网上都没说呢? 4. 注意XmlAttribute和XmlElement的区别。 ...

    使用XmlSerializer时摆脱XmlInclude

    .NET 4 [^]的可序列化的额外类型,可以使用属性来查找您想要的东西。

    主页:.NET的可配置和可扩展Xml序列化器

    经典的System.Xml.XmlSerializer提出了一些挑战: 不支持使用接口类型定义的属性不支持只读集合属性(如Xaml一样) 不支持参数化的构造函数(不可变对象) 不支持私有构造函数不支持使用循环引用的类或具有接口属性...

    XSerializer:与接口一起使用的XML序列化器(!)

    XSerializer的XML序列化处理System.Xml.Serialization.XmlSerializer无法处理的属性和类型,例如接口和字典。 它是BCL XmlSerializer的直接替代品-它使用相同的属性:[XmlElement],[XmlAttribute]等。 // Create ...

    C# XML序列化方法及常用特性总结分析

    Serializer的使用比较直观,需要多注意的是XML序列化相关的Attribute,怎么把这些attribute应用到我们的对象,以及对象公共属性上面去,生成满足预期格式的XML。 这里列出了最常用的方法和特性,涵盖日常大部分的...

    通用管理系统配置源码

    要使一个类可序列化,最简单的方法是使用 Serializable 属性对它进行标记,如下所示: [Serializable] public class Class { } 但是也可以传递类类别。 将类的实例序列化成一个Xml文件核心代码是 ...

    C#对象与XMl文件之间的相互转换

    C#提供三种序列化方式,分别为:1、是使用BinaryFormatter进行串行化;2、使用SoapFormatter进行串行化;3、使用XmlSerializer进行串行化。其中对于BinaryFormatter的方式需要实现ISerializable接口,而XmlSeriializ...

    详解XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度

    分析并操作 responseXML属性  如果你使用 XMLHttpRequest 来获得一个远程的 XML 文档...使用 XMLSerializer 把 DOM 树序列化成字符串或文件。  5.如果你预先知道 XML 文档的内容,你可以使用 RegExp。如果你用 RegE

    xml-serializer:CalDAV-Sync和CardDAV-Sync for Android中使用的xml-serializer

    这是CalDAV-Sync和CardDAV-Sync for Android使用的XML序列化程序。 它的目的是要比现有的Android XmlSerializer接口更方便,但仍要轻巧高效。 该库具有基本的XML序列化功能。 目前,它不支持默认名称空间和漂亮的...

    protobuf-net:惯用.NET的协议缓冲区库

    protobuf-net是用于.NET代码的基于合同的序列化程序,它碰巧以Google设计的“协议缓冲区”序列化格式写入数据。 但是,该API与Google的API截然不同,并且遵循典型的.NET模式(在使用方面,它与XmlSerializer , ...

    OSS.Common:oss基础类库,主要涉及基础实体,加密算法,xml序列化,以及其他扩展方法等

    静态扩展方法(时间,字符串等等处理)基础日志,缓存,配置辅助静态类及默认方案实现全局结果,分页实体定义Authrization用户授权信息模块,可以在上下文中使用MemberShiper,其中主要包含两个属性:AppAuthorize...

Global site tag (gtag.js) - Google Analytics