2017-10-09 72 views
3

我有以下XML文件:與IXmlSerializable的自定義類失敗OutOfMemoryException異常

<MyConfig> 
    <Item a1="Attrib11" a2="Attrib21" a3="Attrib31" /> 
    <Item a1="Attrib12" a2="Attrib22" a3="Attrib32" /> 
</MyConfig> 

我加載它使用以下輔助方法:

public static T Load<T>(string path) 
{ 
    XmlSerializer xml = new XmlSerializer(typeof(T)); 

    using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) 
    using (StreamReader sr = new StreamReader(fs)) 
    { 
     return (T)xml.Deserialize(sr); 
    } 
} 

public static void Save<T>(string path, T contents) 
{ 
    XmlSerializer xml = new XmlSerializer(typeof(T)); 

    using (FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.Read)) 
    using (StreamWriter sw = new StreamWriter(fs)) 
    { 
     xml.Serialize(sw, contents, ns); 
    } 
} 

這是MyConfig

public class MyConfig 
{ 
    [XmlElement("Item")] 
    public List<Item> Items { get; set; } 

    public MyConfig() 
    { 
     Items = new List<Item>(); 
    } 
} 

public class Item : IXmlSerializable 
{ 
    [XmlAttribute()] 
    public string Attrib1 { get; set; } 

    [XmlAttribute()] 
    public string Attrib2 { get; set; } 

    [XmlAttribute()] 
    public string Attrib3 { get; set; } 

    public Item(string attrib1, string attrib2, string attrib3) 
    { 
     Attrib1 = attrib1; 
     Attrib2 = attrib2; 
     Attrib3 = attrib3; 
    } 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     if (reader.MoveToContent() == XmlNodeType.Element) 
     { 
      Attrib1 = reader.GetAttribute("a1"); 
      Attrib2 = reader.GetAttribute("a2"); 
      Attrib3 = reader.GetAttribute("a3"); 
     } 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     writer.WriteAttributeString("a1", Attrib1); 
     writer.WriteAttributeString("a2", Attrib2); 
     writer.WriteAttributeString("a3", Attrib3); 
    } 
} 

然後我有以下測試牀代碼來檢查課程的序列化:

string file = "somePath"; 

MyConfig myConfig = new MyConfig() 
{ 
    Items = new List<Item>() 
    { 
     new Item("Attrib11", "Attrib21", "Attrib31"), 
     new Item("Attrib12", "Attrib22", "Attrib32"), 
    }, 
}; 

Save(file, myConfig); 

MyConfig myConfig2 = Load<MyConfig>(file); 

這會失敗,出現OutOfMemory異常Load,我該如何解決這個問題?檢查文件在somePath,它看起來是正確的。

+0

在你的'ReadXml()'中,你是否正確地使用了外部元素?請參見[正確的方法來實現IXmlSerializable?](https://stackoverflow.com/q/279534)和https://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly – dbc

+0

@dbc I已經把所有相關的代碼放在這裏,所以你告訴我,這是我第一次做一個使用'IXmlSerializable'的類,所以我不太清楚你的意思。我讀了所有的屬性,但如果這就是你的意思。 – TheLethalCoder

回答

2

你需要告訴reader前進到下一個節點,你讀過的屬性後:

public void ReadXml(XmlReader reader) 
{ 
    if (reader.MoveToContent() == XmlNodeType.Element) 
    { 
     Attrib1 = reader.GetAttribute("a1"); 
     Attrib2 = reader.GetAttribute("a2"); 
     Attrib3 = reader.GetAttribute("a3"); 
    } 
    // Go to the next node. 
    reader.Read(); 
} 

如果你不叫reader.Read(),將reader一遍又一遍地讀相同的節點再次,因此XmlSerializer將創建無限量的Item實例,直到最終獲得OutOfMemoryException

+0

因此'reader.Read()'本質上是'reader.MoveToNext()'? – TheLethalCoder

+0

@TheLethalCoder最有可能與'reader.MoveToNext()'相同,但'XmlReader'沒有這樣的方法。所有'reader.MoveToXXX()'方法只是在當前節點內移動'reader',但它們不會將'reader'推進到下一個節點。 – haindl

+1

在我看來,並不是最好的命名方法,它實際上並不太明顯。 – TheLethalCoder