将类的Nullable双重属性Serilize为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(); } } } 

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

您不能将可为空的双XmlText序列化为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) 

该信息是自我解释的。 来自XmlTextAttribute文档的XmlTextAttribute

您可以将XmlTextAttribute应用于返回原始类型和枚举类型的公共字段和公共读/写属性。

您可以将XmlTextAttribute应用于返回字符串数组的字段或属性。 您还可以将该属性应用于Object类型的数组,但必须将Type属性设置为string。 在这种情况下,插入到数组中的任何字符串都被序列化为XML文本。

XmlTextAttribute也可以应用于返回XmlNode或XmlNode对象数组的字段。

要理解为什么ShouldSerializeXXX()在这里没有帮助,你应该理解XmlSerializer 工作原理如下 :

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

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

但是第1步无法访问该类的实例。 它完全基于类型信息创建其动态库。 而且,从类型信息来看,没有办法推断相关的ShouldSerializeXXX()方法在double? value ShouldSerializeXXX()时会返回false double? value double? value为null。 因此,动态代码生成中止,因为无法生成将可空双精度写为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); } } }