`
zz8ss5ww6
  • 浏览: 64893 次
  • 性别: 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
分享到:
评论

相关推荐

    XmlSerializer序列和反序列化Demo

    XmlSerializer序列化与反序列化是C#编程中常见的数据处理技术,主要用于将对象的状态转换为XML格式的字符串,以便存储或传输,然后再从XML字符串恢复为原来的对象状态。这个"XmlSerializer序列和反序列化Demo"是一个...

    Unity序列化和反序列XML并添加属性2

    在本篇文章中,我们将会讲解如何使用 Unity 序列化和反序列 XML,并添加属性来实现游戏中的数据存储和读取。 一、Unity 序列化 Unity 序列化是指将游戏中的数据转换为 XML 格式的字符串,以便存储到文件中。 在 ...

    Android应用中使用XmlSerializer序列化XML数据的教程

    在Android开发中,序列化是将对象转换为可存储或可传输的形式的过程,而XmlSerializer则是Android提供的一个用于XML序列化的工具,可以帮助开发者将数据结构转换成XML格式的字符串或者直接写入到文件中。本教程将...

    序列化窗体所有控件

    对于每个控件,我们可以使用反射获取其属性(如名称、位置、大小等),然后使用XML序列化将这些信息写入XML文件。 例如,我们可能创建一个名为`SerializeFormControls`的方法: ```csharp public void ...

    XmlSerializer使用中的问题

    如果对象包含未指定的类型或属性,或者类型结构不符合 XML 序列化属性的预期,那么序列化过程将会失败。 2. **反序列化问题** 反序列化时,XmlSerializer 尝试根据 XML 文档的结构创建对象实例。如果 XML 文档的根...

    C#和Java的序列化反序列化

    在C#中,我们可以使用.NET框架提供的`System.Runtime.Serialization.Formatters.Binary.BinaryFormatter`类来进行二进制序列化,或者使用`System.Xml.Serialization.XmlSerializer`来进行XML序列化。而在Java中,...

    C#中Font和Color的Xml序列化

    现在,我们可以将这些自定义类作为属性包含在我们的设置类(例如`Settings`)中,然后使用XmlSerializer对整个设置对象进行序列化和反序列化。这样,即使包含Font和Color的设置也可以保存到XML文件并重新加载。 ```...

    XML序列化与反序列化 实战

    在`CustomXmlSerializer.cs`这个文件中,很可能包含了一个自定义的序列化器类,它扩展了标准的XmlSerializer类,提供了更高级的功能,比如添加自定义的序列化行为、处理特定类型的字段或属性,或者优化序列化过程。...

    使用XmlSerializer类将对象序列化为Xml格式保存

    在C#中,我们可以通过在类和属性上添加特定的特性(如`[Serializable]`或`[XmlElement]`)来控制序列化的行为。 ```csharp using System.Xml.Serialization; [Serializable] public class MySerializableObject { ...

    使用XmlSerializer序列化List对象成XML格式(list对象序列化)

    在本文中,我们将深入探讨如何使用`XmlSerializer`来序列化和反序列化一个`List&lt;T&gt;`对象到XML格式。 首先,我们创建一个简单的类`Customer`,它包含`ID`和`Name`属性,这将是我们要序列化的对象类型: ```csharp ...

    序列化反序列化例题net

    在.NET中,我们可以使用内置的序列化机制,如BinaryFormatter、XmlSerializer、DataContractSerializer或者Json.NET(Newtonsoft.Json)等。例如,BinaryFormatter可以将对象转换为二进制流,方便存储到磁盘或在网络...

    C#序列化与反序列化(包括复杂xml对象)

    在C#中,我们可以使用`System.Xml.Serialization`命名空间下的`XmlSerializer`类来实现XML序列化。这个过程可以将一个复杂的对象结构转换成XML字符串,方便存储或在网络上传输。 方法一:反序列化取节点KV值 这种...

    将treeView序列化Xml

    这两个结构体需要使用`[Serializable()]`特性标记,表明它们是可序列化的,这样才能被序列化框架处理。 1. `TreeViewData`结构体: - `Nodes`属性:存储`TreeNodeData`数组,表示`TreeView`的根节点。 - `...

    C#对象三种形式的序列化和反序列化

    - 定义要序列化的类,添加`Serializable`属性。 - 创建序列化器实例,如`BinaryFormatter`、`XmlSerializer`或`SoapFormatter`。 - 使用`Serialize`方法将对象转换为流,然后可以写入文件或发送到网络。 - 对于反...

    C#对象序列化反序列化保存与读取和对象直接保存与读取

    其使用`DataContract`和`DataMember`特性来标记要序列化的类和属性。 - `JsonSerializer`(来自`Newtonsoft.Json`库):广泛用于JSON格式的数据交换,特别适合Web API和JavaScript交互。它的性能较好,且JSON格式...

    四种反序列化与序列化

    使用 `DataContractAttribute` 和 `DataMemberAttribute` 来标记要序列化的类和属性。 - **DataContractSerializer反序列化**:同样,它也能将XML反序列化回对象,使用 `ReadObject` 方法完成此操作。 以上四种...

    C#源码序列化与反序列化

    - 使用`[IgnoreDataMember]`或`[NonSerialized]`属性忽略特定字段不参与序列化。 - `DataContract`和`DataMember`特性允许更细粒度的控制,例如字段排序和是否必需。 5. **XML与JSON序列化示例** ```csharp ...

    XmlDemoTranfer Xml序列化与反序列化

    如果想要控制哪些字段或属性被序列化,可以使用`[XmlElement]`、`[XmlAttribute]`等特性标记。对于不想序列化的成员,可以使用`[XmlIgnore]`特性。 3. **命名空间的处理** 使用`[XmlRoot]`特性可以指定XML根元素的...

    C#对象序列化与反序列化

    - **SOAP序列化**也可以序列化所有可序列化的字段,并通过XML命名空间来保持原始程序集的信息。 - **XML序列化**仅能序列化公共字段或通过公共属性公开的私有字段。XML序列化不会保存完整的类型名称或程序集信息,这...

    C#序列化和反序列化

    XML序列化允许你选择要序列化的特定字段和属性,不包括类型信息。如果需要保留类型信息,可以使用XmlSerializer的子类DataContractSerializer或XmlSerializer。 ```csharp // 序列化 XmlSerializer ...

Global site tag (gtag.js) - Google Analytics