2014-04-11 3 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); 
      } 
     } 
    } 
} 

T는 인터페이스 인 경우 List<T>을 어떻게 serialize 할 수 있습니까?

+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); 
     } 
    } 
} 
관련 문제