2009-11-10 14 views
11

私はこのような構造を持っている:.NET XMLシリアル化と継承

public interface A 
{ 
    public void method(); 
} 

public class B : A 
{ 
} 

public class C : A 
{ 
} 

List<A> list; 

リストは、私が今戻ってデシリアライズ、それをシリアル化することができ、彼らはまた、私は維持したいと思いますいくつかのフィールドを持つタイプBとCのオブジェクトが含まれています適切なオブジェクトインスタンスを取得しますか? 好ましくはXMLへ

EDIT:

インタフェースが含まれています。このリストをシリアル化し、次にBとCのインスタンスに戻って、それをデシリアライズするための任意の簡単な方法はありますか?

答えて

4

You ma試してみてくださいDataContractSerializer

public interface A 
{ 
} 

public class B : A 
{ 
} 

public class C : A 
{ 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<A> list = new List<A>(new A[] { new B(), new C() }); 
     var serializer = new DataContractSerializer(
      list.GetType(), new[] { typeof(B), typeof(C) }); 

     var sb = new StringBuilder(); 
     using (var stringWriter = new StringWriter(sb)) 
     using (var writer = XmlWriter.Create(stringWriter)) 
     { 
      serializer.WriteObject(writer, list); 
     } 

     using (var stringReader = new StringReader(sb.ToString())) 
     using (var reader = XmlReader.Create(stringReader)) 
     { 
      list = (List<A>)serializer.ReadObject(reader); 
     } 

    } 
} 
4

はい、ただし、XmlElement、XmlRoot、およびXmlArray属性を使用して再生する必要があります。 各タイプには独自の要素名が必要です。

EDIT:いくつかのサンプルコード。すべてのクラスは共通の基底クラスから派生しています。ここで

はサンプルコードです:

[XmlRoot(ElementName="Root")] 
public sealed class SomeObject 
{ 

    private BaseObject _Object; 

    [XmlElement(Type=typeof(App.Projekte.Projekt), ElementName="Projekt")] 
    [XmlElement(Type=typeof(App.Projekte.Task), ElementName="Task")] 
    [XmlElement(Type=typeof(App.Projekte.Mitarbeiter), ElementName="Mitarbeiter")] 
    public BaseObject Object 
    { 
     get 
     { 
      return _Object; 
     } 
     set 
     { 
      _Object = value; 
     } 
    } 
} 

EDIT:それは必要ないです(しかし、私のコードから提示されたプロジェクトで必要とされる)、使用していると仮定すると、

+1

'[Serializable]'は必要ありません。 XMLシリアライゼーションでは使用されません。 –

6

としてシリアル化属性を削除建てあなたは次の属性を見てみなければならない.NET XMLシリアル化で:/デシリアライズをするとき

System.Xml.Serialization.XmlIncludeAttribute 

それは他のタイプを含めるようにあなたがシリアライザを指示することができますシリアライズ。

リストに新しいタイプを追加してシリアル化メタデータを更新しないことはよくある間違いです。十分なテストカバレッジがあることを確認してください。あなたのケースでは

0

は次のようにあなたのインタフェースを実装する抽象クラスます

abstract class Abs : A 

、その後、腹筋

public class B : Abs 
public class C : Abs 

と 一覧リストから自分のクラスを派生します。

XmlIncludeAttributeを使用して、型をXmlSerializerの型配列に追加します。

5

インターフェイスの種類をシリアル化できないため、抽象クラスを使用しますが、XmlInclude属性を使用して型をハードコードするのではなく、既知の型をシリアルとシリアルのXmlSerializerに追加します。次のような方法をデシリアライズします。

string listXml = Serialize<List<A>>(ListA, new Type[] { typeof(B), typeof(C) }); 

    List<IA> NewList = Deserialize<List<A>>(listXml, new Type[] { typeof(B), typeof(C) }); 

    private static T Deserialize<T>(string Xml, Type[] KnownTypes) 
    { 
     XmlSerializer xs = new XmlSerializer(typeof(T),KnownTypes); 

     StringReader sr = new StringReader(Xml); 
     return (T)xs.Deserialize(sr); 
    } 

    private static string Serialize<T>(Object obj, Type[] KnownTypes) 
    { 
     StringBuilder sb = new StringBuilder(); 
     using (StringWriter sw = new StringWriter(sb)) 
     { 
      XmlSerializer xs = new XmlSerializer(typeof(T), KnownTypes); 

      xs.Serialize(sw, obj); 
     } 
     return sb.ToString(); 
    } 
0

XmlSerializerはインターフェイスでは機能しません。だから、次のことができます。

または

使用を検討して親の型のためIXmlSerializableを実装し、それをXmlIncludeAttributeを使用するか、またはXmlSerializer

または

にKnownTypesを提供

変換インターフェースその後、抽象クラスへとDataContractSerializer from .NET 3.0