2015-01-23 2 views
3

Я должен сериализовать, используя ниже код: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, используя в качестве текста для узла свойство значение, которое является двойной, но он не работает, даже используя шаблон ShouldSerialize, чтобы избежать сериализации пустых узлов. NodeA и NodeB работают нормально. Мне нужна помощь для NodeC.

ответ

3

Вы не можете сериализовать двойное значение с удлинением как 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:

Вы можете применить XmlTextAttribute к общественным полям и свойствам общественного чтения/записи, которые возвращают примитивные и перечисление типов.

Вы можете применить XmlTextAttribute к полю или свойству, которое возвращает массив строк. Вы также можете применить атрибут к массиву типа Object, но вы должны установить свойство Type в строку. В этом случае любые строки, вставленные в массив, сериализуются как XML-текст.

XmlTextAttribute также может быть применен к полю, которое возвращает XmlNode или массив объектов XmlNode.

Чтобы понять, почему ShouldSerializeXXX() здесь не поможет, вы должны понимать, что XmlSerializerworks as follows:

  1. Первый раз, когда вы сериализовать тип, то XmlSerializer конструктор внутренне пишет время выполнения C# код сериализации и десериализовать экземпляры типа и всех ссылочных типов с помощью отражения, затем компилирует код и загружает полученную DLL в память.

  2. Впоследствии сериализация и десериализация экземпляров классов выполняются ранее созданной динамической DLL.

Но шаг 1 не имеет доступа к экземпляру класса. Он создает свою динамическую библиотеку, основанную исключительно на информации о типе. И из информации о типе нет способа сделать вывод о том, что соответствующий метод ShouldSerializeXXX() вернет false, когда double? value имеет значение NULL. Таким образом, генерация динамического кода прерывается, потому что код для записи nullable double как XmlText не может быть сгенерирован.

В качестве обходного пути, вы могли бы сделать свойство строки, которая представляет двойной:

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); 
     } 
    } 
} 
+1

Спасибо. Теперь он работает нормально. –

Смежные вопросы