c# - 将类的可空双属性序列化为 Xml 文本

标签 c# xml xml-serialization

我必须使用以下代码进行序列化:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace MyExample
{
    class Program
    {
    static void Main(string[] args)
    {
        MyXmlDocument document = new MyXmlDocument();

        document.MyExample.NodeA.value = "Value To Node A";
        document.MyExample.NodeB.value = "Value To Node B";
        document.MyExample.NodeC.value = 1234.567;
        document.WriteToXml(@"C:\Users\E9JR\Desktop\mydocument.xml");
        Console.Write("> Done!");
        Console.ReadKey();
    }
}

[XmlRoot(ElementName="xmlExample",IsNullable=false)]
public class XmlExample
{
    private NodeA_Elem _nodea;
    [XmlElement()]
    public NodeA_Elem NodeA
    {
        get
        {
            return _nodea;
        }
        set
        {
            _nodea = value;
        }
    }
    public bool ShouldSerializeNodeA()
    {
        return !String.IsNullOrEmpty(_nodea.value);
    }

    private NodeB_Elem _nodeb;
    [XmlElement(ElementName = "NodeB", IsNullable = false)]
    public NodeB_Elem NodeB
    {
        get
        {
            return _nodeb;
        }
        set
        {
            _nodeb = value;
        }
    }
    public bool ShouldSerializeNodeB()
    {
        return !String.IsNullOrEmpty(_nodeb.value);
    }

    private NodeC_Elem _nodec;
    [XmlElement(ElementName = "NodeC",IsNullable=false)]
    public NodeC_Elem NodeC
    {
        get
        {
            return _nodec;
        }
        set
        {
            _nodec = value;
        }
    }
    public bool ShouldSerializeNodeC()
    {
        return _nodec.value.HasValue;
    }

    public XmlExample()
    {
        _nodea = new NodeA_Elem();
        _nodeb = new NodeB_Elem();
        _nodec = new NodeC_Elem();
    }
}

public class NodeA_Elem
{
    [XmlText()]
    public string value { get; set; }
}

public class NodeB_Elem
{
    [XmlText()]
    public string value { get; set; }
}

public class NodeC_Elem
{
    [XmlText()]
    public double? value { get; set; }
}

public class MyXmlDocument
{
    private XmlExample _myexample;
    public XmlExample MyExample
    {
        get
        {
            return _myexample;
        }
        set
        {
            _myexample = value;
        }
    }

    public void WriteToXml(string path)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(XmlExample));

        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.Encoding = Encoding.Unicode;

        StringWriter txtwriter = new StringWriter();
        XmlWriter xmlwtr = XmlWriter.Create(txtwriter, settings);
        serializer.Serialize(xmlwtr, MyExample);

        StreamWriter writer = new StreamWriter(path);
        writer.Write(txtwriter.ToString());

        writer.Close();
    }

    public void ReadXml(string path)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(XmlExample));

        StreamReader reader = new StreamReader(path);

        MyExample = (XmlExample)serializer.Deserialize(reader);

    }

    public MyXmlDocument()
    {
        _myexample = new XmlExample();
    }
    }
}

我正在尝试使用 value 属性作为节点的文本来序列化 NodeC,这是一个 double 属性,但它不起作用,即使使用 ShouldSerialize 模式来避免序列化空节点也是如此。 NodeA 和 NodeB 工作正常。我需要 NodeC 方面的帮助。

最佳答案

您不能将可为 null 的 double 值序列化为 XmlText。如果您查看您收到的 System.InvalidOperationException 的完整文本,您将看到如下内容:

   InnerException: System.InvalidOperationException
        Message="Cannot serialize member 'value' of type System.Nullable`1[System.Double]. XmlAttribute/XmlText cannot be used to encode complex types."
        Source="System.Xml"
        StackTrace:
             at System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter)
             at System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns, RecursionLimiter limiter)
             at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)

该消息不言自明。来自 documentation for XmlTextAttribute 的确认:

You can apply the XmlTextAttribute to public fields and public read/write properties that return primitive and enumeration types.

You can apply the XmlTextAttribute to a field or property that returns an array of strings. You can also apply the attribute to an array of type Object but you must set the Type property to string. In that case, any strings inserted into the array are serialized as XML text.

The XmlTextAttribute can also be applied to a field that returns an XmlNode or an array of XmlNode objects.

要了解为什么 ShouldSerializeXXX() 在这里没有帮助,您应该了解 XmlSerializer works as follows :

  1. 第一次序列化类型时,XmlSerializer 构造函数在内部编写运行时 C# 代码以使用反射序列化和反序列化该类型的实例和所有引用类型,然后编译代码并将生成的 DLL 加载到内存中。

  2. 随后,类实例的序列化和反序列化由先前创建的动态 DLL 执行。

但是第1步没有访问类的实例。它完全基于类型信息创建其动态库。并且,从类型信息中,无法推断相关的 ShouldSerializeXXX() 方法在 double? 时会返回 false 为空。因此,动态代码生成中止,因为无法生成将可为空的 double 值写入 XmlText 的代码。

作为变通方法,您可以制作一个表示 double 的字符串属性:

public class NodeC_Elem
{
    [XmlIgnore]
    public double? value { get; set; }

    [XmlText]
    public string StringValue 
    {
        get
        {
            if (value == null)
                return null;
            return XmlConvert.ToString(value.Value);
        }
        set
        {
            if (value == null)
            {
                this.value = null;
                return;
            }
            this.value = XmlConvert.ToDouble(value);
        }
    }
}

关于c# - 将类的可空双属性序列化为 Xml 文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28110589/

相关文章:

c# - Wpf Prism MVVM 模块之间的变化

java - 使用XSLT输出多个文件

java - XStream fromXML() 异常

c# - 直接反/序列化到/从 XML Linq

c# - 确定 int 数组中最常见的元素

c# - 如何使用 System.Speech 和 SAPI 5.3 向已加载的语法添加单词

C#等待多个线程完成

xml - 使用 xmlstarlet 进行 XPath 查询

c# - 如何在 C# 中将 CSHTML 读取为 XML 文件

java - 4 字节 UTF-8 序列的字节 2 无效,但仅在执行 JAR 时?