2016-03-30 5 views
0

Zum BeispielGibt es eine Möglichkeit, Dictionary, der den abstrakten Typ enthält, mit DataContractSerializer zu serialisieren?

[DataContract] 
public abstract class BaseClass 
{ 
    public abstract string id { get; set; } 
} 

[DataContract(Name = "class1")] 
public class concreteClass1 : BaseClass 
{ 
    public concreteClass1() { } 

    [DataMember] 
    public override string id { get; set; } 

    [DataMember] 
    public string prop1 { get; set; } 

    [DataMember] 
    public string prop2 { get; set; } 

} 

[DataContract(Name = "class2")] 
public class concreteClass2 : BaseClass 
{ 
    public concreteClass2() { } 

    [DataMember] 
    public override string id { get; set; } 

    [DataMember] 
    public string prop1 { get; set; } 

    [DataMember] 
    public string prop2 { get; set; } 

} 

Wenn ich versuche, ein Wörterbuch enthält eine der konkreten Klassen wie diese

static public void Main(string[] args){ 

    Dictionary<string, BaseClass> items = new Dictionary<string, BaseClass>(); 
    items.Add("1", new concreteClass1() { id = "1", prop1 = "blah1" }); 
    items.Add("11", new concreteClass1() { id = "11", prop1 = "blah11" }); 

    var serializer = new DataContractSerializer(items.GetType()); 
    string xmlString = string.Empty; 
    using (var sw = new StringWriter()) 
    { 
     using (var writer = new XmlTextWriter(sw)) 
     { 
      writer.Formatting = System.Xml.Formatting.Indented; 
      serializer.WriteObject(writer, items); 
      writer.Flush(); 
      xmlString = sw.ToString(); 
     } 
    } 

} 

ich diesen Fehler serialisiert werden, wenn zu Writeobject versuchen

Typ ‚ConsoleTest .Program + Base 'kann nicht serialisiert werden. Markieren Sie mit dem DataContractAttribute-Attribut und markieren Sie alle Elemente, die mit dem DataMemberAttribute-Attribut serialisiert werden sollen. Wenn es sich bei dem Typ um eine Sammlung handelt, sollten Sie sie mit dem Attribut CollectionDataContractAttribute markieren. Weitere unterstützte Typen finden Sie in der Microsoft .NET Framework-Dokumentation .

Gibt es eine Möglichkeit, dies zu lösen?

EDIT: Ich habe auch versucht Knowntype auf der Basisklasse verwenden, aber es nicht

[DataContract] 
    [KnownType(typeof(concreteClass1))] 
    [KnownType(typeof(concreteClass2))] 
    public abstract class BaseClass 
    { 
     public abstract string id { get; set; } 
    } 
+0

Was ist TL in der folgenden Codezeile? serializer.WriteObject (writer, TL) ; – iCode

+0

@iCode Tippfehler sorry – erotavlas

+0

Ich dachte, es war aber notwendig, um zu klären. Ich habe Ihren Code in ein Testprojekt kopiert ... Ich habe eine Codezeile hinzugefügt, um den xmlString in die Konsole zu schreiben, und er hat für mich funktioniert. Ich wollte das XML hier nicht kopieren, aber es hat funktioniert. Versuchen Sie, den Codeblock using (var sw = new StringWriter()) in einen try catch einzufügen und Details zur Ausnahme anzuzeigen. – iCode

Antwort

1

versuchen, dies funktionierte ...

mit ....

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Runtime.Serialization; 
using System.Xml; 

Klassen ...

[DataContract] 
[KnownType(typeof(concreteClass1))] 
[KnownType(typeof(concreteClass2))] 
public abstract class BaseClass 
{ 
    [DataMember] 
    public abstract string id { get; set; } 
} 

[DataContract(Name = "class1")] 
public class concreteClass1 : BaseClass 
{ 
    public concreteClass1() { } 

    [DataMember] 
    public override string id { get; set; } 

    [DataMember] 
    public string prop1 { get; set; } 

    [DataMember] 
    public string prop2 { get; set; } 

} 

[DataContract(Name = "class2")] 
public class concreteClass2 : BaseClass 
{ 
    public concreteClass2() { } 

    [DataMember] 
    public override string id { get; set; } 

    [DataMember] 
    public string prop1 { get; set; } 

    [DataMember] 
    public string prop2 { get; set; } 

} 

code ....

static void Main(string[] args) 
    { 
     Dictionary<string, BaseClass> items = new Dictionary<string, BaseClass>(); 
     items.Add("1", new concreteClass1() { id = "1", prop1 = "blah1" }); 
     items.Add("11", new concreteClass1() { id = "11", prop1 = "blah11" }); 
     // this should work too.... 
     items.Add("999", new concreteClass2() { id = "999", prop1 = "blah999" }); 
     items.Add("888", new concreteClass2() { id = "888", prop1 = "blah888" }); 

     //Serialize(items); 

     var serializer = new DataContractSerializer(items.GetType()); 
     string xmlString = string.Empty; 
     try 
     { 
      using (var sw = new StringWriter()) 
      { 
       using (var writer = new XmlTextWriter(sw)) 
       { 
        writer.Formatting = System.Xml.Formatting.Indented; 
        serializer.WriteObject(writer, items); 
        writer.Flush(); 
        xmlString = sw.ToString(); 
       } 
      } 
     } 
     catch (Exception) 
     { 

      throw; 
     } 
    } 

///////////////////// UPDATE /////////////////// //

Als ein bisschen ein Bonus (nicht das Gefühl eared ich meine 25 Punkte noch) hier sind zwei Funktionen, die ein generisches Objekt wird serialise und deserialise .....

 public static void Serialize<T>(T data) 
     { 
      try // try to serialize the collection to a file 
      { 
       using (Stream stream = File.Open("data.xml", FileMode.Create)) 
       { 
        // create DataContractSerializer 
        DataContractSerializer serializer = new DataContractSerializer(typeof (T)); 
        // serialize the collection (EmployeeList1) to file (stream) 
        serializer.WriteObject(stream, data); 
       } 
      } 
      catch (IOException) 
      { 
      } 
     } 

     public static T Deserialize<T>() where T : new() 
     { 
      // Create an instance of T 
      T ReturnListOfT = CreateInstance<T>(); 

      // Try to Deserialize from file stream 
      try 
      { 
       using (Stream stream = File.Open("data.xml", FileMode.Open)) 
       { 
        // create DataContractSerializer 
        DataContractSerializer serializer = new DataContractSerializer(typeof (T)); 
        // deserialize the collection (Employee) from file (stream) 
        ReturnListOfT = (T)serializer.ReadObject(stream); 
       } 
      } 
      catch (IOException) 
      { 
      } 

      return (T)ReturnListOfT; 
     } 

     // function to create instance of T 
     public static T CreateInstance<T>() where T : new() 
     { 
      return (T)Activator.CreateInstance(typeof(T)); 
     } 

statt Wenn Sie das XML manuell ändern müssen, können Sie das Objekt (aus einer Datei, im Beispiel 'data.xml') unter Verwendung Ihrer vorhandenen Klassen deserialisieren und eine Benutzerschnittstelle erstellen, die dem Benutzer erlaubt Ändern Sie die Eigenschaften des Objekts \ classes und speichern Sie dann das geänderte Objekt erneut in eine Datei.

+0

Aber ID ist abstrakte Eigenschaft, Ich muss es implementieren – erotavlas

+0

Mein Fehler, es serialisiert 'id' (zu einer Zeichenfolge) Ich serialisierte in eine Datei und konnte es nicht dort sehen, wird das wieder überprüfen .. Sie Klassen wo richtig und ich habe meine Antwort geändert. ... – Monty

+0

Ich habe auch versucht NetDataContractSerializer und es funktioniert besser - es tatsächlich die Typen serialisiert korrekt, jedoch ist die XML-Ausgabe viel komplexer und weniger benutzerfreundlich (falls Sie Änderungen manuell vornehmen mussten) – erotavlas

Verwandte Themen