2017-02-07 3 views
1

У меня есть два класса: «компания», полученная из Treenode и «document».Сериализация/десериализация XML, полученного из Treenode

[Serializable] 
[XmlRoot("Company")] 
public class Company : TreeNode, IXmlSerializable 
{ 
    private string _x; 
    private string _y; 

    public Company() { } 

    [XmlElement("X")] 
    public string X { get; set; } 
    [XmlElement("Y")] 
    public string Y { get; set; } 


    public System.Xml.Schema.XmlSchema GetSchema() 
    { 
     return null; 
    } 
    public void ReadXml(XmlReader reader) 
    { 
     if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "Company") 
     { 
      x = reader["X"].ToString; 
      y = reader["Y"].ToString;   
     } 
    } 
    public void WriteXml(XmlWriter writer) 
    { 
     writer.WriteElementString("X", this.X.ToString()); 
     writer.WriteElementString("Y", this.Y.ToString()); 
    } 
} 

public class Document 
{ 
    private int _id; 
    private string _name; 
    private Company _company; 

    public Document() { } 

    [XmlElement("ID")] 
    public int ID { get; set; } 
    [XmlElement("Name")] 
    public string Name { get; set; } 
    [XmlElement("Company")] 
    public Company Comp { get; set; } 
} 

Когда я пытаюсь сериализовать документ, а затем сохранить в файл, его работу. Но когда я десериализую, параметр читателя всегда равен нулю. Любые решения?

Это мой код для десериализации. «sr» является переменной, которая содержит текст xml.

var sr = new StreamReader(ms); 
var myStr = sr.ReadToEnd(); 

XmlSerializer serializer = new XmlSerializer(typeof(List<Document>)); 
using (TextReader tr = new StringReader(myStr)) 
{ 
    List<Document> docu = (List<Document>)serializer.Deserialize(tr); 
} 

Я пытаюсь реализовать ISerialization и отладку, но никогда не стрелял, и попытаться overide сериализации и десериализации метод, и не повезло.

Я использую .NET Framework 3.5

+0

Вы проверили полученный XML? – Fildor

+0

@Fildor Да, у меня есть чек. При десериализации данные компании никогда не заполняются. – Blishton

+0

Попробуйте удалить методы IXmlSerializable и GetSchema, ReadXml и WriteXML в классе компании. Затем повторите попытку. – Fildor

ответ

2

Как объяснена в this article, внедрение IXmlSerializable правильно, на самом деле довольно сложно. Ваша реализация ReadXml(), нарушает требование о том, что потребляют самое оболочку элемент, а также все содержимое, например, так:

public void ReadXml(System.Xml.XmlReader reader) 
{ 
    reader.MoveToContent(); 
    // Read attributes 
    Boolean isEmptyElement = reader.IsEmptyElement; // (1) 
    reader.ReadStartElement(); 
    if (!isEmptyElement) // (1) 
    { 
     // Read Child elements X and Y 

     // Consume the end of the wrapper element 
     reader.ReadEndElement(); 
    } 
} 

Кроме того, reader["X"] возвращает значение атрибутаXML с именем "X", как объяснено в docs. В вашем WriteXml() вы написали значения X и Y как вложенные Элементы XML. Это объясняет NullReferenceException. Вам нужно исправить ваши методы чтения и записи, чтобы они были согласованными.

Однако, я хотел бы предложить альтернативу реализации IXmlSerializable, который должен ввести суррогатного типа для Company. Во-первых, extract все не- TreeNode свойства Company в интерфейсе:

public interface ICompany 
{ 
    string X { get; set; } 
    string Y { get; set; } 
} 

public class Company : TreeNode, ICompany 
{ 
    public Company() { } 

    public string X { get; set; } 
    public string Y { get; set; } 
} 

Это необязательно, но делает код более понятным. Затем ввести суррогатной ПОКО, который реализует тот же интерфейс, но не наследует от TreeNode:

public class CompanySurrogate : ICompany 
{ 
    public string X { get; set; } 
    public string Y { get; set; } 

    public static implicit operator CompanySurrogate(Company company) 
    { 
     if (company == null) 
      return null; 
     // For more complex types, use AutoMapper 
     return new CompanySurrogate { X = company.X, Y = company.Y }; 
    } 

    public static implicit operator Company(CompanySurrogate surrogate) 
    { 
     if (surrogate == null) 
      return null; 
     // For more complex types, use AutoMapper 
     return new Company { X = surrogate.X, Y = surrogate.Y }; 
    } 
} 

Обратите внимание, что суррогатное может быть неявно преобразован в исходный Company типа? Теперь вы можете использовать суррогат в XML-сериализации, установив свойство XmlElementAttribute.Type атрибута быть у суррогатной:

public class Document 
{ 
    public Document() { } 

    [XmlElement("ID")] 
    public int ID { get; set; } 
    [XmlElement("Name")] 
    public string Name { get; set; } 

    [XmlElement("Company", Type = typeof(CompanySurrogate))] 
    public Company Comp { get; set; } 
} 

Это исключает все возможности ошибок в реализации IXmlSerializable. Учитывая следующий список ввода:

var list = new List<Document> 
{ 
    new Document { Name = "my name", ID = 101, Comp = new Company { X = "foo", Y = "bar", NodeFont = new System.Drawing.Font("Arial", 10) } }, 
    new Document { Name = "2nd name", ID = 222, Comp = new Company { X = "tlon", Y = "ukbar" } }, 
}; 

Следующая XML можно будет генерироваться, и может быть десериализован успешно:

<ArrayOfDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Document> 
     <ID>101</ID> 
     <Name>my name</Name> 
     <Company> 
      <X>foo</X> 
      <Y>bar</Y> 
     </Company> 
    </Document> 
    <Document> 
     <ID>222</ID> 
     <Name>2nd name</Name> 
     <Company> 
      <X>tlon</X> 
      <Y>ukbar</Y> 
     </Company> 
    </Document> 
</ArrayOfDocument> 

Это, как говорится, я не рекомендую этот дизайн. Ваш пользовательский интерфейс должен есть вашей модели данных, он не должен be ваша модель данных. См., Например, How does one implement UI independent applications?.Замена Company на ICompany по возможности может быть первым шагом на пути к изменению дизайна; вам может быть легче заменить существующую архитектуру TreeNode, которая выглядит так:

public class CompanyNode : TreeNode 
{ 
    public ICompany Company { get; set; } 
}