Polymorphe Typen und IXmlSerializable

9

Die XML-Serialisierung in .NET ermöglicht polymorphe Objekte über den Parameter extraTypes[] des Konstruktors XmlSerializer . Es ermöglicht auch die Anpassung der XML-Serialisierung für Typen, die IXmlSerializable implementieren.

Allerdings kann ich diese beiden Funktionen nicht kombinieren - wie in diesem minimalen Beispiel gezeigt:

%Vor%

Die letzte Zeile zeigt System.InvalidOperationException mit dieser Nachricht an:

  

Der Typ CsFoo.CustomSerializable darf in diesem Kontext nicht verwendet werden   Verwenden Sie CsFoo.CustomSerializable als Parameter, return   Typ oder Mitglied einer Klasse oder Struktur, der Parameter return   type oder member muss als Typ CsFoo.CustomSerializable deklariert werden   (Es kann nicht Objekt sein). Objekte vom Typ CsFoo.CustomSerializable   kann nicht in nicht typisierten Auflistungen wie ArrayLists verwendet werden.

Wenn wir durch die dynamisch generierten XML-Assemblies blättern, kommen wir letztendlich zurück zum .NET-Standardbibliothekscode, indem wir aufrufen:

%Vor%

Dies führt wiederum zu:

%Vor%

Reflector zeigt, dass die XmlInvalidSerializable Ressource der obigen Zeichenfolge entspricht - d. h. WriteTypedPrimitive mag IXmlSerializable nicht.

Wenn wir einen nicht-polymorphen Serializer erzeugen, so:

%Vor%

.NET generiert einen Aufruf an:

%Vor%

Dies behandelt IXmlSerializable richtig. Weiß jemand, warum .NET diese Funktion nicht im polymorphen Fall verwendet? Betrachtet man die C #, die der XML-Serializer erzeugt, so scheint mir dies relativ einfach zu sein. Hier ist ein Code, den ich vom XML-Serializer bekommen habe, mit einer nicht getesteten Lösung:

%Vor%

Ist dies aus technischen Gründen oder nur eine Funktionseinschränkung weggelassen? Nicht unterstützte Funktion oder meine Idiotie? Meine Intertubes Google-Fähigkeiten scheitern mir.

Ich habe einige verwandte Fragen hier gefunden, mit " C # Xml- Serialisieren einer abgeleiteten Klasse mit IXmlSerializable "ist am relevantesten. Es lässt mich glauben, dass es einfach nicht möglich ist.

In diesem Fall besteht mein aktueller Gedanke darin, eine Standardprozedur IXmlSerializable in die Root-Basisklasse zu injizieren. Dann wird alles ein IXmlSerializable , und .NET wird sich nicht beschweren. Ich kann Reflection.Emit verwenden, um die Körpern ReadXml und WriteXml für jeden konkreten Typ auszulöschen, wobei XML erzeugt wird, das genauso aussehen würde wie wenn ich die Bibliothek verwenden würde.

Einige Leute denken, wenn sie mit einem XML-Serialisierungsproblem konfrontiert werden: "Ich weiß, ich benutze Reflection.Emit, um Code zu generieren." Jetzt haben sie zwei Probleme.

P.S. Hinweis; Ich kenne Alternativen zu .NETs XML-Serialisierung und weiß, dass es Einschränkungen gibt. Ich weiß auch, dass das Speichern eines POCO wesentlich einfacher ist als der Umgang mit abstrakten Datentypen. Aber ich habe einen Stapel Legacy-Code und brauche Unterstützung für bestehende XML-Schemas.

So wie ich Antworten schätze, die zeigen, wie einfach das ist in SomeOtherXML , YAML , XAML , ProtocolBuffers , DataContract , RandomJsonLibrary , Thrift oder Ihre MorseCodeBasedSerializeToMp3 library - hey ich könnte etwas lernen -, was ich hoffe, ist eine XML-Serializer Work-Around, wenn nicht Lösung.

    
Jaap Suter 10.03.2009, 19:18
quelle

3 Antworten

2

Ich konnte Ihr Problem reproduzieren, wenn Sie object verwenden:

%Vor%

Ich habe dann jedoch eine abgeleitete Klasse von CustomSerializable erstellt:

%Vor%

Und versuchte es zu serialisieren:

%Vor%

Das hat funktioniert.

Es scheint also, dass das Problem auf den Fall beschränkt ist, in dem Sie "object" als den zu serialisierenden Typ angeben, aber nicht, wenn Sie einen konkreten Basistyp angeben.

Ich werde am Morgen mehr darüber recherchieren.

    
John Saunders 28.07.2009 03:18
quelle
1

Zuerst Poster Erklärung

  

Die XML-Serialisierung in .NET ermöglicht polymorphe Objekte über den Parameter extraTypes [] des XmlSerializer-Konstruktors.

ist irreführend. Laut MSDN wird extratypes für Folgendes verwendet:

  

Wenn eine Eigenschaft oder ein Array zurückgibt, gibt der Parameter extraTypes Objekte an, die in das Array eingefügt werden können.

Bedeutet, dass, wenn irgendwo in Ihrem serialisierten Objekt Graph polymorphe Objekte über ein Array zurückgegeben werden, diese verarbeitet werden können.

Obwohl ich nicht wirklich eine Lösung gefunden habe, wie man einen polymorphen Typ als root-XML-Objekt serialisiert, war ich in der Lage, polymorphe Typen im Objektgraphen zu serialisieren, entweder mit XML-Serialisierer oder IXmlSerializable. Siehe unten für meine Lösung:

%Vor%

Beachten Sie, dass Sie entweder

verwenden %Vor%

oder

%Vor%

Ohne das definierte XmlElement würde der Code bei der Serialisierung fehlschlagen.

    
Rok 13.05.2011 23:21
quelle
0

Damit IxmlSerializable funktioniert, muss die Klasse einen Nullkonstruktor haben.

Betrachten Sie eine Basisklasse

  • MyBaseXmlClass: IXmlSerializable
    - Implementiere GetSchema
  • MyXmlClass: MyBaseXmlClass
    - ReadXml
    • WriteXml
david valentine 29.07.2009 01:09
quelle

Tags und Links