Partager via


Sérialisation avec tolérance de version

Dans les versions 1.0 et 1.1 de .NET Framework, la création de types sérialisables qui pouvaient être utilisés d'une version à l'autre d'une même application était problématique. Si un type était modifié par l'ajout de champs supplémentaires, les problèmes suivants se produisaient :

  • Les versions antérieures d'une application levaient des exceptions lorsqu'on leur demandait de désérialiser de nouvelles versions du type antérieur.

  • Les nouvelles versions d'une application levaient des exceptions lorsqu'on leur demandait de désérialiser des versions antérieures d'un type avec des données manquantes.

La technologie VTS (Version Tolerant Serialization, Sérialisation avec tolérance de version) est un ensemble de fonctionnalités introduites dans .NET Framework 2.0, qui facilite la modification des types sérialisables au fil du temps. Spécifiquement, les fonctionnalités VTS sont activées pour les classes auxquelles l'attribut SerializableAttribute a été appliqué. Ces fonctionnalités permettent d'ajouter de nouveaux champs à ces classes sans annuler la compatibilité avec les autres versions du type. Pour découvrir un exemple d'application opérationnel, reportez-vous à la section Version Tolerant Serialization Technology Sample.

Elles sont activées lorsque vous utilisez BinaryFormatter. En outre, toutes les fonctionnalités, à l'exception de la tolérance des données superflues, sont également activées lorsque vous utilisez le SoapFormatter. Pour plus d'informations sur l'utilisation de ces classes pour la sérialisation, voir Sérialisation binaire.

Notes

La fonctionnalité de tolérance des données superflues pour le BinaryFormatter est susceptible d'être disponible ultérieurement pour .NET Framework 1.1 sous forme de correctif.

Liste des fonctionnalités

L'ensemble des fonctionnalités inclut :

  • Tolérance des données superflues ou inattendues. Permet aux nouvelles versions du type d'envoyer des données aux versions antérieures.

  • Tolérance des données facultatives manquantes. Permet aux versions antérieures d'envoyer des données aux nouvelles versions.

  • Rappels de sérialisation. Active le paramètre de valeur par défaut intelligent lorsque des données sont manquantes.

En outre, une fonctionnalité permet de déclarer l'ajout d'un champ facultatif. Il s'agit de la propriété VersionAdded de l'attribut OptionalFieldAttribute.

Ces fonctionnalités sont abordées en détail ci-après.

Tolérance des données superflues ou inattendues

Dans le passé, lors de la désérialisation, toutes les données superflues ou inattendues généraient la levée d'exceptions. Avec les fonctionnalités VTS, dans la même situation, toutes les données superflues ou inattendues sont ignorées au lieu d'entraîner la levée d'exceptions. Cela permet aux applications qui utilisent de nouvelles versions d'un type (des versions qui incluent davantage de champs) d'envoyer des informations aux applications qui attendent des versions antérieures du même type.

Dans l'exemple de code suivant, les données supplémentaires contenues dans le champ CountryField de la version 2.0 de la classe Address sont ignorées lorsqu'une application antérieure désérialise la nouvelle version.

// Version 1 of the Address class.
[Serializable]
public class Address
{
    public string Street;
    public string City;
}
// Version 2.0 of the Address class.
[Serializable]
public class Address
{
    public string Street;
    public string City;
    // The older application ignores this data.
    public string CountryField;
}
' Version 1 of the Address class.
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
End Class

' Version 2.0 of the Address class.
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
    ' The older application ignores this data.
    Public CountryField As String
End Class

Tolérance des données manquantes

Les champs peuvent être marqués comme facultatifs en leur appliquant l'attribut OptionalFieldAttribute. Lors de la désérialisation, si des données facultatives sont manquantes, le moteur de sérialisation ignore leur absence et ne lève aucune exception. Ainsi, les applications qui attendent des versions antérieures d'un type peuvent envoyer des données aux applications qui attendent des versions plus récentes du même type.

L'exemple de code suivant présente la version 2.0 de la classe Address avec le champ CountryField marqué comme facultatif. Si une application antérieure envoie la version 1 à une application plus récente qui attend la version 2.0, l'absence des données est ignorée.

[Serializable]
public class Address
{
    public string Street;
    public string City;

    [OptionalField]
    public string CountryField;
}
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String

    <OptionalField> _
    Public CountryField As String
End Class

Rappels de sérialisation

Les rappels de sérialisation sont un mécanisme qui fournit des raccordements au processus de sérialisation/désérialisation en quatre points.

Attribut Lorsque la méthode associée est appelée Utilisation classique

OnDeserializingAttribute

Avant la désérialisation.*

Initialise les valeurs par défaut pour les champs facultatifs.

OnDeserializedAttribute

Après la désérialisation.

Corrige les valeurs des champs facultatifs en fonction du contenu des autres champs.

OnSerializingAttribute

Avant la sérialisation.

Prépare la sérialisation. Par exemple, crée des structures de données facultatives.

OnSerializedAttribute

Après la sérialisation.

Enregistre les événements de sérialisation.

* Ce rappel est appelé avant le constructeur de désérialisation, s'il est présent.

Utilisation des rappels

Pour utiliser les rappels, appliquez l'attribut approprié à une méthode qui accepte un paramètre StreamingContext. Seule une méthode par classe peut être marquée avec chacun de ces attributs. Par exemple :

[OnDeserializing]
private void SetCountryRegionDefault(StreamingContext sc)
{
    CountryField = "Japan";
}
[OnDeserializing]
private void SetCountryRegionDefault(StreamingContext sc)
{
    CountryField = "Japan";
}

Ces méthodes sont destinées au versioning. Lors de la désérialisation, un champ facultatif peut ne pas être correctement initialisé si les données de ce champ sont manquantes. Ce problème peut être corrigé en créant la méthode qui assigne la valeur correcte, puis en appliquant l'attribut OnDeserializingAttribute ou OnDeserializedAttribute à la méthode.

L'exemple de code suivant présente la méthode dans le contexte d'un type. Si une version antérieure d'une application envoie une instance de la classe Address à une version ultérieure de l'application, les données du champ CountryField seront manquantes. Mais après la désérialisation, le champ sera défini à la valeur par défaut "Japan".

[Serializable]
public class Address
{
    public string Street;
    public string City;
    [OptionalField]
    public string CountryField;

    [OnDeserializing]
    private void SetCountryRegionDefault (StreamingContext sc)
    {
        CountryField = "Japan";
    }
}
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
    <OptionalField> _
    Public CountryField As String

    <OnDeserializing> _
    Private Sub SetCountryRegionDefault(StreamingContext sc)
        CountryField = "Japan";
    End Sub
End Class

Propriété VersionAdded

L'attribut OptionalFieldAttribute a la propriété VersionAdded. Dans la version 2.0 de .NET Framework, il n'est pas utilisé. Néanmoins, il est important de définir cette propriété correctement afin de s'assurer que le type sera compatible avec les futurs moteurs de sérialisation.

La propriété indique la version d'un type à laquelle un champ donné a été ajouté. Elle doit être incrémentée de 1 exactement (en commençant par 2) à chaque fois que le type est modifié, comme indiqué dans l'exemple de code suivant :

// Version 1.0
[Serializable]
public class Person
{
    public string FullName;
}

// Version 2.0
[Serializable]
public class Person
{
    public string FullName;

    [OptionalField(VersionAdded = 2)]
    public string NickName;
    [OptionalField(VersionAdded = 2)]
    public DateTime BirthDate;
}

// Version 3.0
[Serializable]
public class Person
{
    public string FullName;

    [OptionalField(VersionAdded=2)]
    public string NickName;
    [OptionalField(VersionAdded=2)]
    public DateTime BirthDate;

    [OptionalField(VersionAdded=3)]
    public int Weight;
}
' Version 1.0
<Serializable> _
Public Class Person
    Public FullName
End Class

' Version 2.0
<Serializable> _
Public Class Person
    Public FullName As String

    <OptionalField(VersionAdded := 2)> _
    Public NickName As String
    <OptionalField(VersionAdded := 2)> _
    Public BirthDate As DateTime
End Class

' Version 3.0
<Serializable> _
Public Class Person
    Public FullName As String

    <OptionalField(VersionAdded := 2)> _
    Public NickName As String
    <OptionalField(VersionAdded := 2)> _
    Public BirthDate As DateTime

    <OptionalField(VersionAdded := 3)> _
    Public Weight As Integer
End Class

Méthodes conseillées

Pour garantir un comportement de versioning correct, suivez ces règles lors de la modification d'un type d'une version à une autre :

  • Ne supprimez jamais un champ sérialisé.

  • N'appliquez jamais l'attribut NonSerializedAttribute à un champ si cet attribut n'a pas été appliqué à ce champ dans la version précédente.

  • Ne changez jamais le nom ou le type d'un champ sérialisé.

  • Lorsque vous ajoutez un champ sérialisé, appliquez l'attribut OptionalFieldAttribute.

  • Lorsque vous supprimez un attribut NonSerializedAttribute d'un champ (qui n'était pas sérialisable dans une version antérieure), appliquez l'attribut OptionalFieldAttribute.

  • Pour tous les champs facultatifs, définissez des paramètres par défaut significatifs à l'aide des rappels de sérialisation, excepté si 0 ou null sont autorisés comme paramètres par défaut.

Pour vous assurer de la compatibilité d'un type avec les futurs moteurs de sérialisation, procédez comme suit :

  • Définissez toujours correctement la propriété VersionAdded sur l'attribut OptionalFieldAttribute.

  • Évitez le versioning avec branches.

Voir aussi

Référence

SerializableAttribute
BinaryFormatter
SoapFormatter
VersionAdded
OptionalFieldAttribute
OnDeserializingAttribute
OnDeserializedAttribute
OnDeserializingAttribute
OnSerializedAttribute
StreamingContext
NonSerializedAttribute

Autres ressources

Sérialisation binaire