Frage

Ich versuche, einen Baum von Knoten Objekte zu serialisieren und deserialisieren. Meine abstrakten „Node“ Klasse sowie anderen abstrakten und konkreten Klassen, die sich daraus ableiten, sind in meinem „Informa“ Projekt definiert. Darüber hinaus habe ich eine statische Klasse in Informa für die Serialisierung / Deserialisierung erstellt.

Zuerst ich dekonstruiert meinen Baum in eine flache Liste des Typs Wörterbuch (guid, Knoten) , wo guid ist die eindeutige ID von Knoten.

Ich bin in der Lage alle mit einem Problem meines Knoten serialisiert. Aber wenn ich versuche deserialisieren ich die folgenden Ausnahme erhalten.

  

Fehler in Zeile 1, Position 227. Element   ‚ http://schemas.microsoft.com/2003/10/Serialization/Arrays : Wert ‘   enthält die Daten der   'Informa: Building' Datenvertrag. Das   Deserializer hat keine Kenntnisse auf jedem   Typ, der zu diesem Vertrag abbildet. Hinzufügen   der Typ ‚Gebäude‘ entspricht,   in die Liste der bekannten Typen - für   beispielsweise durch das usying   Knowntype oder durch das Hinzufügen   die Liste der bekannten Arten übergeben   Datacontract Serializer.

Alle Klassen, die von Knoten ableiten, einschließlich Gebäude, haben die [Knowntype (typeof (Typ t))] Attribut auf sie angewendet.

Meine Serialisierung und Deserialisierung Methoden sind unter:

public static void SerializeProject(Project project, string filePath)
{
    try
    {
        Dictionary<Guid, Node> nodeDic = DeconstructProject(project);

        Stream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None);

        //serialize

        DataContractSerializer ser = new DataContractSerializer(typeof(Dictionary<Guid, Node>),"InformaProject","Informa");

        ser.WriteObject(stream,nodeDic);

        // Cleanup
        stream.Close();
    }
    catch (Exception e)
    {
        MessageBox.Show("There was a problem serializing " + Path.GetFileName(filePath) + ". \n\nException:" + e.Message, "Doh!", MessageBoxButtons.OK, MessageBoxIcon.Error);
        throw e;
    }

}



public static Project DeSerializeProject(string filePath)
{
    try
    {
        Project proj;

        // Read the file back into a stream
        Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);

        DataContractSerializer ser = new DataContractSerializer(typeof(Dictionary<Guid, Node>), "InformaProject", "Informa");

        Dictionary<Guid, Node> nodeDic = (Dictionary<Guid, Node>)ser.ReadObject(stream);

        proj = ReconstructProject(nodeDic);        

        // Cleanup
        stream.Close();

        return proj;

    }
    catch (Exception e)
    {
        MessageBox.Show("There was a problem deserializing " + Path.GetFileName(filePath) + ". \n\nException:" + e.Message, "Doh!", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

}
War es hilfreich?

Lösung

  

Alle Klassen, die von Knoten ableiten,   einschließlich Gebäude, haben die   [Knowntype (typeof (Typ T))] -Attribut   angewandt zu ihnen.

KnownType ist in der Regel auf die Basis angelegt Typ - d. H

[DataContract, KnownType(typeof(Building)), ...]
abstract class Node { ... }

(beachten Sie - Sie auch die bekannten Typen im DataContractSerializer Konstruktor angeben können, ohne Attribute erforderlich)

EDIT RE Ihre Antwort

Wenn die framwork Klasse nicht weiß, über alle abgeleiteten Typen, dann müssen Sie die bekannten Typen angeben, wenn die Serializer erstellen:

[DataContract] abstract class SomeBase { }
[DataContract] class Foo : SomeBase { }
[DataContract] class Bar : SomeBase { }
...
// here the knownTypes argument is important
new DataContractSerializer(typeof(SomeBase),
      new Type[] { typeof(Foo), typeof(Bar) });

Dies kann mit kombiniert werden (zum Beispiel) preserveObjectReferences usw. durch die null im vorherigen Beispiel zu ersetzen.

END EDIT

Doch ohne etwas reproduzierbar (das heißt Node und Building), wird es viel zu schwer sein, zu helfen.

Die andere seltsame Sache; Bäume Strukturen sind sehr gut , um Dinge wie DataContractSerializer - es gibt in der Regel keine Notwendigkeit, sie zuerst zu glätten, da Bäume können trivialerweise in XML ausgedrückt werden. Haben Sie wirklich brauchen, es zu glätten?


Beispiel:

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

[DataContract, KnownType(typeof(Building))]
abstract class Node {
    [DataMember]
    public int Foo {get;set;}
}
[DataContract]
class Building : Node {
    [DataMember]
    public string Bar {get;set;}
}

static class Program
{
    static void Main()
    {
        Dictionary<Guid, Node> data = new Dictionary<Guid, Node>();
        Type type = typeof(Dictionary<Guid, Node>);
        data.Add(Guid.NewGuid(), new Building { Foo = 1, Bar = "a" });
        StringWriter sw = new StringWriter();
        using (XmlWriter xw = XmlWriter.Create(sw))
        {
            DataContractSerializer dcs = new DataContractSerializer(type);
            dcs.WriteObject(xw, data);
        }

        string xml = sw.ToString();

        StringReader sr = new StringReader(xml);
        using (XmlReader xr = XmlReader.Create(sr))
        {
            DataContractSerializer dcs = new DataContractSerializer(type);
            Dictionary<Guid, Node> clone = (Dictionary<Guid, Node>)
                dcs.ReadObject(xr);
            foreach (KeyValuePair<Guid, Node> pair in clone)
            {
                Console.WriteLine(pair.Key + ": " + pair.Value.Foo + "/" +
                    ((Building)pair.Value).Bar);
            }
        }
    }
}

Andere Tipps

Alles klar hier ist ein Diagramm, das die Dinge klar machen sollte. Ich entwickle ein Plugin für ein anderes Programm, das Beziehungen und Eigenschaften nicht bereits in das Programm erstellt. Diese Beziehungen / Eigenschaften sind in meiner Baumstruktur definiert. Aber ich versuche, diese Struktur abstrakt zu definieren, so dass ich Implementierungen des Plugins für verschiedene Programme erstellen können, sowie den Zugang der Informationen von mehreren Implementierungen in einem einzigen „viewer“ Programm.

Meine Serialize / Deserialize Methoden werden im Rahmen definiert, aber der Rahmen nicht weiß, über alle Implementierungen. Ich habe gehofft, ich vermeiden, könnte die Implementierungsprojekte zu den Speichern / Öffnen / serialize / deserialize Methoden im Rahmen Projekt eine Liste von Typen passieren zu müssen, aber es scheint, dass ich dies nicht vermeiden können? Ich denke, wenn der Sinn, die serialize / deserialize Methoden müssen Zugang zu den Typen haben sie Deserialisieren.

http://dl.getdropbox.com/u/113068/informa_framework.jpg <--- Größere Version alt text http://dl.getdropbox.com/u/113068/informa_framework.jpg

So ist dies nicht wirklich das Problem mit Gebäuden erklären, da es eine konkrete Klasse im Rahmen Projekt. Ich denke, was passiert ist, wenn ich die DataContractSerializer Zugang hat Serialisierung auf alle Objekte und deren KnowType Parameter und speichert sie richtig. Aber wenn ich deserialisieren ich meine DataContractSerializer mit Wörterbuch als Typ erstellen. So ist es kennt nur Knoten, aber nicht die abgeleiteten Klassen von Knoten.

new DataContractSerializer(typeof(Dictionary<Guid, Node>))

Ich kann es nicht sagen, was alle abgeleiteten Typen sind, weil, wie ich sagte, dass sie in anderen Projekten, die das Rahmenprojekt nicht kennt. Soooooooo scheint die beste Lösung, jede Implementierung haben, ist eine Liste von Knotentypen übergeben sie an die Serialisierung und Deserialisierung Methoden im Rahmen Projekt verwendet.

Ist das sinnvoll? Gibt es einen besseren Weg, dies zu tun?

Was ist der Unterschied zwischen diesen beiden Verwendungen der KnownTypes zuschreiben? Ich wusste nicht, dass Sie könnte / möchte festlegen, dass eine Klasse eine Knowntype eines anderen ist.

[DataContract]
[KnownType(typeof(Building))]
abstract class Node {
    [DataMember]
    public int Foo {get;set;}
}
[DataContract]
class Building : Node {
    [DataMember]
    public string Bar {get;set;}
}

[DataContract] 
[KnownType(typeof(Node))]
abstract class Node {
    [DataMember]
    public int Foo {get;set;}
}
[KnownType(typeof(Building))]
class Building : Node {
    [DataMember]
    public string Bar {get;set;}
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top