Question

Je dois travailler un vieux application qui a utilisé BinaryFormatter pour sérialiser les données d'application dans filestream (disons dans un fichier nommé « data.oldformat ») sans optimizazion la classe principale a été marquée avec l'attribut

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

et le code de sérialisation

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

Dans une tentative d'optimiser le processus de sérialisation / désérialisation J'ai simplement fait la classe implémente l'interface ISerializable et écrit quelques routines de sérialisation optimisés

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

L'optimisation fonctionne très bien, mais je dois trouver un moyen de reatrive les données contenues dans les anciens fichiers de compatibilité descendante.

Comment puis-je faire ??

Pierluigi

Était-ce utile?

La solution

stmax a une excellente réponse, mais je voudrais la mettre en œuvre comme celui-ci, qui utilise SerializationEntry.GetEnumerator() au lieu de try/catch. De cette façon est plus propre et beaucoup plus rapide.

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.");
    }
}

Je préférerais une version LINQ utilisant .FirstOrDefault (), mais SerializationInfo ne met pas en œuvre IEnumerable -. Face, assez bizarrement, il n'implémente même pas l'ancienne interface IEnumerable

Autres conseils

puisque vous avez déjà implémenté l'interface ISerializable, vous avez probablement déjà ajouté le constructeur nécessaire:

public MainClass(SerializationInfo info, StreamingContext context) {}

vous pouvez utiliser l'info-objet passé au constructeur pour récupérer des données à partir du fichier sérialisé. par défaut (à savoir quand aucun ISerializable est mis en oeuvre), les noms des champs sont utilisés comme identificateurs lors de sérialisation. donc si votre ancienne classe avait un champ « int x », vous pouvez désérialiser cela en utilisant:

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

pour les versions plus récentes i ajouter normalement une entrée "version" pendant la sérialisation, comme ceci:

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

lors de la désérialisation, vous pouvez vérifier cette entrée de version et désérialiser en conséquence:

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.");
    }
}

Je n'ai pas compilé ce code, peut contenir des fautes de frappe.

espoir qui aide.

Juste essayer la même chose que vous avez fait jusqu'à présent

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

Mise en œuvre ISerializable n'a pas changé votre classe d'origine, vous avez fondamentalement juste ajouté quelques méthodes

Lors de la sérialisation vos objets ajouter un champ version supplémentaire (cela ne devrait pas ajouter trop de frais généraux). Ensuite, dans votre méthode de GetObjectData, essayez de récupérer le champ de la première version et selon que celle-ci existe ou non (en attrapant le SerializationException) désérialiser l'ancienne ou la nouvelle façon. L'ancienne aura juste sérialisé toutes les données que vous devriez juste pouvoir appeler ... Obtenir tous les champs.

Votre code précédent devrait fonctionner. Avez-vous une exception? Essayez d'utiliser le nouveau constructeur:

 Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top