2017-02-07 9 views
1

Treenodeから派生した "company"と "document"という2つのクラスがあります。Treenodeから派生したXMLのシリアライズ/逆シリアル化

[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; } 
} 

ドキュメントをシリアル化しようとすると、そのファイルに保存されます。しかし、私はdeserialize時、リーダーパラメータは常にnullです。どんな解決策ですか?

これは逆シリアル化のためのコードです。 "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とデバッグを実装しようとしたが解雇決して、およびシリアル化およびデシリアライズする方法、および運をオーバライドしてみてください。

私が正しくIXmlSerializableを実装し、

+0

結果XMLを確認しましたか? – Fildor

+0

@Fildorはい、私は小切手を持っています。デシリアライズすると、会社のデータが一杯になることはありません。 – Blishton

+0

CompanyクラスのIXmlSerializableメソッドとGetSchemaメソッド、ReadXmlメソッド、およびWriteXMLメソッドを削除してみます。その後、もう一度試してください。 – Fildor

答えて

2

としてはthis articleで説明したの.NET Framework 3.5を使用していますことは、実際にはかなりトリッキーです。説明したように

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"]は、"X"という名前XML属性の値を返します。ReadXml()の実装ではそうは次のように、それは、ラッパー要素自体だけでなく、すべてのコンテンツを消費要件に違反するように見えますdocsにあります。 WriteXml()では、XYの値をXML要素のネストとして書きました。これはNullReferenceExceptionについて説明しています。一貫性を保つためには、読み書きメソッドを修正する必要があります。

しかし、私はあなたのためにCompany代理タイプを導入することである、IXmlSerializableを実装する代わりにお勧めしたいです。まず、インターフェースにextractCompanyの全ての非TreeNode特性:

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; } 
} 

これは任意であるが、コードがより明確となります。

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型に変換することができ:次に、同じインターフェイスを実装していますがTreeNodeから継承していないサロゲートPOCOをご紹介!今、あなたは、サロゲートのことをするXmlElementAttribute.Type属性プロパティを設定することで、XMLシリアル化でサロゲートを使用することができます。

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> 

言われていること、私は本当にこのデザインはお勧めしません。あなたのUIはになりますあなたのデータモデルは、になるべきではありませんあなたのデータモデル。たとえばHow does one implement UI independent applications?を参照してください。可能であればCompanyICompanyに置き換えることは、デザインを変更するための第一歩です。既存のアーキテクチャを次のようなTreeNodeに置き換える方が簡単になることがあります。

public class CompanyNode : TreeNode 
{ 
    public ICompany Company { get; set; } 
} 
関連する問題