In Anlehnung an meine vorherige Frage habe ich daran gearbeitet, mein Objektmodell in XML zu serialisieren. Aber ich bin jetzt auf ein Problem gestoßen (quelle Überraschung!).
Das Problem, das ich habe, ist, dass ich eine Sammlung habe, die von einem abstrakten Basisklassentyp ist, der von den konkreten abgeleiteten Typen gefüllt wird.
Ich dachte, es wäre in Ordnung, nur die XML-Attribute allen beteiligten Klassen hinzuzufügen, und alles wäre pfirsichfarben. Leider ist das nicht der Fall!
Also habe ich ein bisschen bei Google gegraben und verstehe jetzt, warum es nicht funktioniert. Dadurch , dass das XmlSerializer
ist in der Tat eine kluge Reflexion um serialize tun Objekte zu / von XML, und seit seinem auf der Grundlage der abstrakten Art, es nicht herausfinden kann , was zum Teufel , um es spricht . Fein.
Ich bin auf diese Seite in CodeProject gestoßen, die anscheinend sehr hilfreich ist (noch nicht vollständig gelesen / konsumiert), aber ich dachte, ich möchte dieses Problem auch in die StackOverflow-Tabelle aufnehmen, um zu sehen, ob Sie eine ordentliche haben Hacks / Tricks, um dies so schnell wie möglich zum Laufen zu bringen.
Eine Sache, die ich auch hinzufügen sollte, ist, dass ich den Weg NICHT gehen möchte XmlInclude
. Es gibt einfach zu viel Kopplung damit, und dieser Bereich des Systems befindet sich in einer intensiven Entwicklung, so dass es ein echtes Wartungsproblem wäre!
quelle
Antworten:
Problem gelöst!
OK, also bin ich endlich da (zugegebenermaßen mit viel Hilfe von hier !).
Fassen Sie also zusammen:
Tore:
Identifizierte Probleme / zu beachtende Punkte:
Die Lösung
Ich habe eine generische Klasse erstellt, in der Sie den generischen Typ als den abstrakten Typ angeben, mit dem Sie arbeiten werden. Dies gibt der Klasse die Möglichkeit, zwischen dem abstrakten Typ und dem konkreten Typ zu "übersetzen", da wir das Casting hart codieren können (dh wir können mehr Informationen erhalten als der XmlSerializer).
Ich habe dann die IXmlSerializable- Schnittstelle implementiert , dies ist ziemlich einfach, aber beim Serialisieren müssen wir sicherstellen, dass wir den Typ der konkreten Klasse in das XML schreiben, damit wir ihn beim De-Serialisieren zurücksetzen können. Es ist auch wichtig zu beachten, dass es vollständig qualifiziert sein muss, da sich die Baugruppen, in denen sich die beiden Klassen befinden, wahrscheinlich unterscheiden. Es gibt natürlich eine kleine Typprüfung und Dinge, die hier passieren müssen.
Da der XmlSerializer nicht umgewandelt werden kann, müssen wir den Code dafür bereitstellen, damit der implizite Operator dann überladen wird (ich wusste nicht einmal, dass Sie dies tun können!).
Der Code für den AbstractXmlSerializer lautet:
Wie können wir den XmlSerializer von dort aus anweisen, mit unserem Serializer und nicht mit dem Standard zu arbeiten? Wir müssen unseren Typ innerhalb der Xml-Attribute type-Eigenschaft übergeben, zum Beispiel:
Hier können Sie sehen, dass eine Sammlung und eine einzelne Eigenschaft verfügbar gemacht werden. Alles, was wir tun müssen, ist , der XML-Deklaration den Parameter type namens hinzuzufügen. : D.
HINWEIS: Wenn Sie diesen Code verwenden, würde ich mich sehr über ein Shout-Out freuen. Es wird auch helfen, mehr Leute in die Community zu bringen :)
Nun, aber unsicher, was wir mit den Antworten hier anfangen sollen, da sie alle ihre Vor- und Nachteile hatten. Ich werde diejenigen aufrüsten, die ich für nützlich halte (keine Beleidigung für diejenigen, die es nicht waren) und dies abschließen, sobald ich den Repräsentanten habe :)
Interessantes Problem und viel Spaß zu lösen! :) :)
quelle
private
oderprotected
erzwingen kann, dass er anderen Klassen nicht zur Verfügung steht.Eine Sache, die Sie sich ansehen sollten, ist die Tatsache, dass Sie im XmlSerialiser-Konstruktor ein Array von Typen übergeben können, die der Serialiser möglicherweise nur schwer auflösen kann. Ich musste das einige Male verwenden, wenn eine Sammlung oder ein komplexer Satz von Datenstrukturen serialisiert werden musste und diese Typen in verschiedenen Assemblys usw. lebten.
XmlSerialiser-Konstruktor mit dem Parameter extraTypes
BEARBEITEN: Ich möchte hinzufügen, dass dieser Ansatz gegenüber XmlInclude-Attributen usw. den Vorteil hat, dass Sie einen Weg finden können, eine Liste Ihrer möglichen konkreten Typen zur Laufzeit zu ermitteln und zusammenzustellen und sie einzufügen.
quelle
Im Ernst, ein erweiterbares Framework von POCOs wird niemals zuverlässig in XML serialisiert. Ich sage das, weil ich garantieren kann, dass jemand mitkommt, Ihre Klasse erweitert und sie verpfuscht.
Sie sollten die Verwendung von XAML zum Serialisieren Ihrer Objektdiagramme in Betracht ziehen. Es wurde entwickelt, um dies zu tun, während die XML-Serialisierung dies nicht tut.
Der Xaml-Serializer und -Deserializer verarbeitet Generika problemlos, auch Sammlungen von Basisklassen und Schnittstellen (sofern die Sammlungen selbst
IList
oder implementierenIDictionary
). Es gibt einige Einschränkungen, z. B. das Markieren Ihrer schreibgeschützten Sammlungseigenschaften mit demDesignerSerializationAttribute
, aber die Überarbeitung Ihres Codes zur Behandlung dieser Eckfälle ist nicht so schwierig.quelle
Nur ein kurzes Update dazu habe ich nicht vergessen!
Ich mache nur noch ein paar Nachforschungen und sehe aus, als wäre ich auf dem Weg zu einem Gewinner. Ich muss nur den Code sortieren.
Bisher habe ich folgendes:
Dieses Verhalten scheint überschrieben werden zu können (Code ausstehend), indem eine Proxy-Klasse erstellt wird, die als Vermittler für den Serializer fungiert. Dies bestimmt im Grunde den Typ der abgeleiteten Klasse und serialisiert diese dann wie gewohnt. Diese Proxy-Klasse speist dann dieses XML in die Zeile des Hauptserialisierers ein.
Schau dir diesen Raum an! ^ _ ^
quelle
Es ist sicherlich eine Lösung für Ihr Problem, aber es gibt ein anderes Problem, das Ihre Absicht, ein "portables" XML-Format zu verwenden, etwas untergräbt. Schlimme Dinge passieren, wenn Sie sich entscheiden, Klassen in der nächsten Version Ihres Programms zu ändern, und Sie beide Serialisierungsformate unterstützen müssen - das neue und das alte (weil Ihre Clients immer noch ihre alten Dateien / Datenbanken verwenden oder eine Verbindung zu ihnen herstellen Ihr Server verwendet die alte Version Ihres Produkts). Sie können diesen Serializer jedoch nicht mehr verwenden, da Sie ihn verwendet haben
das sieht aus wie
das heißt, Ihre Assembly-Attribute und Version ...
Wenn Sie nun versuchen, Ihre Assembly-Version zu ändern, oder wenn Sie sie signieren möchten, funktioniert diese Deserialisierung nicht ...
quelle
Ich habe ähnliche Dinge getan. Normalerweise stelle ich sicher, dass sich alle XML-Serialisierungsattribute in der konkreten Klasse befinden, und lasse nur die Eigenschaften dieser Klasse die Basisklassen aufrufen (falls erforderlich), um Informationen abzurufen, die beim Aufrufen des Serializers de / serialisiert werden diese Eigenschaften. Es ist ein bisschen mehr Codierungsarbeit, aber es funktioniert viel besser als der Versuch, den Serializer zu zwingen, genau das Richtige zu tun.
quelle
Noch besser mit Notation:
quelle