编程语言
首页 > 编程语言> > c#-将类的Nullable double属性序列化为XmlText

c#-将类的Nullable double属性序列化为XmlText

作者:互联网

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

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,这是一个两倍,但是即使使用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

>第一次序列化类型时,XmlSerializer构造函数在内部编写运行时c#代码以使用反射对类型和所有引用类型的实例进行序列化和反序列化,然后编译代码并将结果DLL加载到内存中.
>随后,由先前创建的动态DLL执行类实例的序列化和反序列化.

但是第1步无权访问该类的实例.它纯粹基于类型信息创建其动态库.并且,从类型信息中,无法推断出当double时相关的ShouldSerializeXXX()方法将返回false吗?值是null.因此,动态代码生成将中止,因为无法生成将XmlText写入可为空的double的代码.

解决方法是,您可以创建一个表示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);
        }
    }
}

标签:xml-serialization,xml,c
来源: https://codeday.me/bug/20191120/2046840.html