2014-04-11 44 views
2

我得到一個對象,它必須從一個通用接口繼承,並且它有一個從該接口作爲屬性的列表。如何序列化接口列表?

要序列化它後面的問題,因爲XmlSerialzer無法確定我的MyClass.Items列表元素中的實際類型。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.Text; 
using System.Xml; 
using System.Xml.Serialization; 

namespace MyTest 
{ 
    public interface IMyInterface 
    { 
     string TestProperty { get; set; } 
    } 
    public class MyClass : IMyInterface 
    { 
     public string TestProperty { get; set; } 
     public List<IMyInterface> Items { get; set; } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyClass obj = new MyClass() { TestProperty = "Test" }; 
      XmlSerializer xs = new XmlSerializer(typeof(MyClass)); // <- throws System.NotSupportedException 
      using (XmlWriter xw = XmlWriter.Create("file.xml", new XmlWriterSettings() 
      { 
       Encoding = Encoding.UTF8, 
       Indent = true, 
       NewLineHandling = NewLineHandling.Entitize 
      })) 
      { 
       xs.Serialize(xw, obj); 
      } 
     } 
    } 
} 

我如何序列化List<T>,其中T是一個接口?

+0

稍微偏離主題,你有沒有考慮有兩類:'MyClass的:IMyInterface'和'MyClassList:名單'。純粹是爲了分開責任? – oleksii

+0

是的,但是1.導致相同的問題,2.在我的範圍內,MyClass將成爲MyClassList。 – modiX

+0

問題是:你爲什麼要[從列表繼承](http://stackoverflow.com/q/5376203/1997232)?不知道你是否遇到過與List <>屬性相同的問題。如果你這樣做,那麼至少你現在可以使用基類而不是接口。如果基類可以序列化自己,那麼你肯定可以序列化基類的數組。 – Sinatr

回答

1

不幸的是,它不支持開箱即用,但它是可行的。您將不得不使用IXmlSerializable接口並編寫自定義序列。它不應該那麼困難 - 你需要枚舉整個列表,獲取每個對象的基礎類型併爲此類型創建一個新的XmlSerializer。反序列化可能會有點棘手,因爲您需要解析類名以確定運行時類型。

+0

我接受了你的回答,因爲它讓我朝着正確的方向前進。我的解決方案是低於這個答案。 – modiX

1

因此,基於decPLs的答案,我創建了一個類來完成這項工作。 T必須是一個接口,它會工作:

public class InterfaceCollection<T> : Collection<T>, IXmlSerializable where T : class 
{ 
    private string Namespace { get; set; } 
    private string Assembly { get; set; } 

    public InterfaceCollection() 
    { 
    } 

    public InterfaceCollection(IList<T> list, string namespaceOfInheritedTypes = null, string assemblyOfInheritedTypes = null) 
     : base(list) 
    { 
     this.Namespace = namespaceOfInheritedTypes ?? null; 
     this.Assembly = assemblyOfInheritedTypes ?? null; 
    } 

    public InterfaceCollection(string namespaceOfInheritedTypes, string assemblyOfInheritedTypes = null) 
    { 
     this.Namespace = namespaceOfInheritedTypes ?? null; 
     this.Assembly = assemblyOfInheritedTypes ?? null; 
    } 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     this.Namespace = reader.GetAttribute("fromNamespace"); 
     this.Assembly = reader.GetAttribute("fromAssembly"); 

     reader.MoveToContent(); 
     while (reader.Read()) 
     { 
      if (reader.NodeType == XmlNodeType.Element) 
      { 
       Type type; 
       if (this.Assembly != null) 
       { 
        type = Type.GetType(this.Namespace + "." + reader.Name + ", " + this.Assembly); 
       } 
       else 
       { 
        type = Type.GetType(this.Namespace + "." + reader.Name); 
       } 
       if (type != null) 
       { 
        XmlSerializer xs = XmlSerializer.FromTypes(new[] { type })[0]; 
        this.Items.Add((T)xs.Deserialize(reader)); 
       } 
      } 
     } 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     writer.WriteAttributeString("fromNamespace", this.Namespace); 
     if (this.Assembly != null) writer.WriteAttributeString("fromAssembly", this.Assembly); 
     foreach (T element in this) 
     { 
      Type type = element.GetType(); 
      XmlSerializer xs = XmlSerializer.FromTypes(new[] { type })[0]; 
      xs.Serialize(writer, element); 
     } 
    } 
}