2009-05-07 8 views
12

Ich muss einige Klassen und Datenstrukturen in einer Datei speichern. Mein erster Reflex war, XML oder binäre Serialisierung zu verwenden, aber das wird zu einem Albtraum. Ich habe eine Reihe von Klassen, die nicht serialisiert werden sollten (private Setter, keine parameterlosen Konstruktoren, kein Serialisierungsattribut, Wörterbücher usw.). Wenn ich bedenke, dass ich diese Klassen nicht ändern kann, was soll ich tun? Gibt es eine Problemumgehung und weiterhin Serialisierung?Wie serialisiert man Klassen, die nicht serialisiert wurden?

Muss ich den ganzen Code schreiben, um die Eigenschaften, Sammlungen usw. zu schreiben?

+0

gute Frage, können Sie auf die Leistungsanforderungen und das Ausmaß des Problems zur Hand gehen. –

+0

An diesem Punkt habe ich eigentlich keine Anforderungen. Ich suche die eleganteste Lösung. – Martin

+1

Sie können wirklich keine Lösung für ein Zero-Requirements-Problem entwerfen :) Egal, welche Lösung Sie wählen, es ist wahrscheinlich die falsche Lösung. Es gibt wirklich keine Möglichkeit, dies zu beantworten, wenn es keine Anforderungen gibt ... –

Antwort

9

Verwenden Sie den JavaScriptSerializer. Es befindet sich im System.Web.Script.Serialization-Namespace und ist im 3.5-Framework in der System.Web.Extensions.dll-Assembly implementiert.

Mit dieser Klasse können Sie jedes POCO serialisieren, unabhängig davon, ob es als [Serializable] markiert ist oder nicht. Ihr Programm muss keine Webanwendung zur Verwendung der JSON-Serialisierung sein.Hier ein Beispiel:

public class Unserializable 
{ 
    public int Age { get; set; } 
    public int ID { get; set; } 
    public string Name { get; set; } 
} 

public class Program 
{ 
    static void Main() 
    { 
    var u = new Unserializable 
      { 
       Age = 40, 
       ID = 2, 
       Name = "Betty" 
      }; 
    var jser = new JavaScriptSerializer(); 
    var jsonText = jser.Serialize(u); 
    // next line outputs {"Age":40,"ID":2,"Name":"Betty"} 
    Console.WriteLine(jsonText); 
    } 
} 
+0

+1 für das wusste ich nicht. Geht das auch mit Feldern um? –

+0

Ja, es behandelt auch Felder. Versuchen Sie dies: öffentliche Klasse UNSerializable { public int Alter; public int ID {erhalten; einstellen; } public string Name {get; einstellen; } public Unserializable (int age, int id, Zeichenfolgenname) { Alter = Alter; ID = id; Name = Name; } } var u = neu unsialisierbar (40, 2, "Donna"); var jser = new JavaScriptSerializer(); var jsonText = jser.Serialize (u); Console.WriteLine ("Serialized {0} using" + "JavaScriptSerializer in {1}:", u.GetType(). Name, jsonText); Dies gibt JSON-Text für das Objekt mit dem öffentlichen Feld als '{"Age": 40, "ID": 2, "Name": "Donna"} aus. –

0

Ich würde einen Code gen Tool (MyGeneration, T4, was auch immer) die DTOs zu erzeugen serialise ...

+0

Das Problem mit dem Code, der dir den Ausweg gibt, ist, dass du, wenn sich die Klasse ändert, erneut Code schreiben musst. Dies kann oder kann kein Problem sein. –

+0

Ich sehe keinen Grund zu -1 dieser ... –

0

Keine einfache Abhilfe.

Wahrscheinlich möchten Sie nur die Felder (privat und öffentlich) in den Klassen serialisieren/deserialisieren und das rekursiv tun. Sie müssen wahrscheinlich Reflektion verwenden, um an sie heranzukommen. Eigenschaften nicht de/serialisieren, da beim Festlegen eines Eigenschaftswerts möglicherweise Nebenwirkungen auftreten. Sie müssen auch alle Felder, die Objekte sind, rekursiv de/serialisieren. Die Herausforderung besteht darin, zu wissen, wo man aufhören soll.

Sie müssen einige große Vermutungen über die Deserialisierung eines serialisierten Objekts mit Reflektion machen. Ich muss davon ausgehen, dass einige der Felder dieser Objekte Verweise auf andere Objekte enthalten, und Sie müssen auch wissen, wie Sie das alles durchgehen.

Zusätzlich müssen Sie die parametrisierten Konstruktoren aufrufen und hoffen, dass Sie beim Setzen von Feldern mit Reflektion nicht zu viel Schaden anrichten.

Kurz gesagt, Sie könnten besser einen speziellen Satz von Wrapper-Klassen erstellen, der Ihre proprietären Klassen in einem serialisierten Format neu erstellt. Ihre Spezialklassen könnten dann serialisiert werden. Dies wird keine einfache Aufgabe sein.

Das heißt, Code Gen könnte möglicherweise die Aufgabe der Identifizierung aller Felder in den Klassen vereinfachen.

0

Eine weitere Option ist die Verwendung eines Adaptermusters.

Gute Nachricht ist, dass Sie die ursprüngliche Klasse nicht ändern müssen. Schlechte Nachrichten sind, dass Sie am Ende wahrscheinlich doppelt so viel Code schreiben werden wie in der ersten "unveränderbaren" Klasse.

Sie erhalten zwei neue Klassen: den Adapter und die neue serializable-Klasse.

Die Idee ist, dass der Adapter weiß, wie die serizliable Klasse erstellt wird, indem die unsialializable Klasse untersucht. Um den anderen Weg (serialisierbar zu unserialisierbar) zu gehen, können Sie wieder einen Adapter verwenden (natürlich gehe ich hier davon aus, dass Ihre privaten Setter tatsächlich über den parametrisierten Konstruktor gesetzt werden).

Here's the pattern in detail.

0

Es gibt zwei separate Teile zu diesem:

  1. Extrahieren/Einstellung der Daten
  2. Speichern/es aus einer Datei (oder einen anderen Ort) Lesen

Für die erster Teil, wenn Sie die Klassen, die Sie serialisieren/deserialisieren wollen, nicht ändern können, bleibt Ihnen nur noch eine tiefe Kopie durch Reflexion.

Für die Serialisierung gehen Sie durch jedes Mitglied der Klasse, die ihren Wert speichert.

Verwenden Sie das Medium, in dem Sie es speichern möchten, z. B. XML, und schreiben Sie diese Werte auf die Festplatte.

Für die Deserialisierung, lesen Sie die Werte aus der Datei ein, erstellen Sie eine neue Instanz des Objekts und verwenden Sie die Reflektion, um alle Werte festzulegen.

Wenn Sie alle Mitglieder erhalten/setzen, haben Sie ein Objekt, das sich in einem identischen Zustand befindet. (Möglicherweise müssen Sie rekursiv durch alle Ihre Objekte gehen, wenn Sie komplexe Mitglieder haben.)

Was, wie Sie speichern die Daten auf der Festplatte, xml oder binäre beide arbeiten. Wenn Sie es sehen und es für den Menschen lesbar haben wollen, dann gehen Sie mit XML. (Ich würde dies für Ihren ersten Stich empfehlen, da es Debugging viel einfacher macht.)

7

Klingt wie ein Job für ... Serialisierung Surrogate!

Zum http://msdn.microsoft.com/en-us/magazine/cc188950.aspx

für einen Überblick.

+0

+1: Surrogates werden nett mit BinaryFormatter spielen. –

+0

Link dead, Archiv hier: https://web.archive.org/web/20141231105711/http://msdn.microsoft.com/en-us/magazine/cc188950.aspx, oder MSDN: https: // msdn. microsoft.com/en-us/library/system.runtime.serialization.surrogateselector(v=vs.110).aspx –

0

Es hängt wirklich von der Größe Ihres Problems und der Leistung ab, die Sie benötigen.

Wenn Sie 1 Problemklasse haben, würde ich nur eine Ersatzklasse schreiben, die diese Klasse serialisieren/deserialisieren kann. Wenn Sie über 100 Klassen sprechen, müssen Sie wahrscheinlich ein Serialisierungsframework verwenden, das alle Feinheiten unterstützt. Keine parameterlose Konstruktion ist ein Albtraum, egal welches Serialisierungs-Framework Sie schreiben oder verwenden, Sie müssen die Parameter im Vorfeld kennen, um sie an den Konstruktor zu übergeben. Private Setter/Wörterbücher/Listen usw. sind kein allzu großes Problem.

Ich schrieb einen mini-serialization Rahmen für die Medien-Browser, die BSD ist. Mein Fokus lag auf der Leistung, aber die Techniken, die ich verwende, können an Ihr Problem angepasst werden. In ähnlicher Weise könnten in Marc's protocol buffers verwendete Techniken verwendet werden.

Wenn Leistung überhaupt nicht wichtig ist, kann ein ziemlich triviales Serialisierungsframework ziemlich schnell codiert werden, das Reflektion verwendet, wird Zeug hart, wenn Sie versuchen, das Ding performant zu halten.

Verwandte Themen