Frage

Ich habe eine eine alte Anwendung arbeiten, dass BinaryFormatter serialisiert Anwendungsdaten in Filestream verwendet (etwa in einer Datei mit dem Namen „data.oldformat“) ohne optimizazion hat die Hauptklasse mit dem Attribut markiert

<serializable()>public MainClass
....... 
end class

und die Serialisierungscode

dim b as new binaryformatter
b.serialize(mystream,mymainclass)

In einem Versuch, die Serialisierung / Deserialisierung zu optimieren Ich habe einfach die Klasse den ISerializable-Schnittstelle implementieren und schrieb einige optimierte Serialisierung Routinen

<serializable()>public MainClass
       implements ISerializable
....... 
end class

Die Optimierung funktioniert wirklich gut, aber ich muss einen Weg finden, um die Daten innerhalb der alten Dateien für die Abwärtskompatibilität reatrive.

Wie kann ich das tun ??

Pierluigi

War es hilfreich?

Lösung

Stmax eine ausgezeichnete Antwort hat, aber ich würde es so implementieren, welche Anwendungen statt SerializationEntry.GetEnumerator() try/catch. Auf diese Weise ist sauberer und deutlich schneller.

public MainClass(SerializationInfo info, StreamingContext context) {
    int version = 0;
    foreach (SerializationEntry s in info)
    {
        if (s.Name == "version") 
        {
            version = (int)s.Value;
            break;
        }
    }

    switch (version) {
      case 0:
        // deserialize "old format"
        break;
      case 1:
        // deserialize "new format, version 1"
        break;
      default:
        throw new NotSupportedException("version " + version + " is not supported.");
    }
}

Ich würde eine LINQ-Version lieber mit .FirstOrDefault (), aber SerializationInfo nicht implementiert IEnumerable -. In Gesicht, bizarr genug, es nicht einmal die alte IEnumerable-Schnittstelle implementieren

Andere Tipps

, da Sie bereits die ISerializable-Schnittstelle implementiert haben, haben Sie wahrscheinlich bereits auch die erforderliche Konstruktor hinzugefügt:

public MainClass(SerializationInfo info, StreamingContext context) {}

Sie können das Info-Objekt an den Konstruktor übergeben Daten aus der serialisierten Datei abzurufen. standardmäßig (das heißt, wenn kein ISerializable implementiert ist), werden die Felder Namen als Bezeichner während der Serialisierung verwendet. also, wenn Sie Ihre alte Klasse ein Feld „int x“ hatte können Sie deserialisieren dies mit:

this.x = info.GetInt32("x");

für neuere Versionen i normalerweise einen „Version“ -Eintrag bei der Serialisierung hinzufügen, wie diese:

public void GetObjectData(SerializationInfo info, StreamingContext context) {
  info.AddValue("version", 1);
  info.AddValue("othervalues", ...);
}

bei der Deserialisierung können Sie diese Version Eintrag überprüfen und deserialisieren entsprechend:

public MainClass(SerializationInfo info, StreamingContext context) {
    int version;
    try {
       version = info.GetInt32("version");
    }
    catch {
       version = 0;
    }

    switch (version) {
      case 0:
        // deserialize "old format"
        break;
      case 1:
        // deserialize "new format, version 1"
        break;
      default:
        throw new NotSupportedException("version " + version + " is not supported.");
    }
}

Ich habe nicht kompiliert, dass Code, könnten Fehler enthalten.

Hoffnung, das hilft.

Versuchen Sie einfach, die gleiche Sache, die Sie haben bisher tun

BinaryFormatter b = new BinaryFormatter();
MainClass a = b.DeSerialize(mystream) as MainClass;

Implementierung ISerializable nicht Ihre ursprüngliche Klasse ändern, im Grunde haben Sie gerade einige Methoden hinzugefügt

Wenn die Serialisierung Ihre Objekte fügen Sie eine zusätzliche Version Feld (dies sollte nicht zu viel Aufwand hinzufügen). Dann in Ihrer GetObjectData Methode versuchen, das Versionsfeld erste und basierend auf abzuzurufen, ob diese vorhanden ist oder nicht (durch die SerializationException Fang) deserialisieren die alte Art und Weise oder die neue Art und Weise. Die alte Art und Weise haben wird nur alle Daten serialisiert, so dass Sie nur in der Lage sein sollten, Get ... für alle Felder zu nennen.

sollte Ihr vorheriger Code arbeiten. Haben Sie eine Ausnahme erhalten? Probieren Sie neuen Konstruktor verwenden:

 Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top