La sérialisation en C# avec une classe dérivée

Je suis en train de construire une notification cadre et pour qui je suis la sérialisation et la désérialisation d'une classe de base, à partir de laquelle toutes les classes je veux envoyer pourraient en tirer.

Le problème est que le code compile, mais quand je l'ai fait essayer à sérialiser cette classe de base, je reçois un message d'erreur indiquant que

Système.Moment de l'exécution.La sérialisation.SerializationException: Type 'Xxx.DataContracts.WQAllocationUpdate " dans l'Assembly 'Xxx.DataContract, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null " n'est pas marqué comme sérialisable.

Voici le code :

public class WCallUpdate : NotificationData
{
    private string m_from = "";
    [DataMember]
    public string From
    {
        get { return m_from; }
        set { m_from = value; }
    }
    private WCall m_wCall = new WCall();
    [DataMember]
    public WCall Call
    {
        get { return m_wCall; }
        set { m_wCall = value; }
    }
}

La DataContract pour la Notification est:

///<summary>
///Basic class used in the notification service
///</summary>
[DataContract]
public class NotificationData
{
}

///<summary>
///Enum containing all the events used in the application
///</summary>
[DataContract]
public enum NotificationTypeKey
{
    [EnumMember]
    Default = 0,
    [EnumMember]
    IWorkQueueServiceAttributionAddedEvent = 1,
    [EnumMember]
    IWorkQueueServiceAttributionUpdatedEvent = 2,
    [EnumMember]
    IWorkQueueServiceAttributionRemovedEvent = 3,
}

Le code utilisé pour sérialiser des données est:

    #region Create Message
    ///<summary>
    ///Creates a memoryStream from a notificationData
    ///note: we insert also the notificationTypeKey at the beginning of the
    ///stream in order to treat the memoryStream correctly on the client side
    ///</summary>
    ///<param name="notificationTypeKey"></param>
    ///<param name="notificationData"></param>
    ///<returns></returns>
    public MemoryStream CreateMessage(NotificationTypeKey notificationTypeKey, NotificationData notificationData)
    {
        MemoryStream stream = new MemoryStream();
        BinaryFormatter formatter = new BinaryFormatter();
        try
        {
            formatter.Serialize(stream, notificationTypeKey);
            formatter.Serialize(stream, notificationData);
        }
        catch (Exception ex)
        {
            Logger.Exception(ex);
        }
        return stream;
    }
    #endregion

Lorsque j'essaie de créer un message:

WCallUpdate  m_wCallUpdate = new WCallUpdate();
NotificationTypeKey  m_notificationTypeKey = new NotificationTypeKey.Default;
CreateMessage(notificationTypeKey , wCallUpdate );

J'ai eu l'erreur suivante:

System.Runtime.Serialization.SerializationException: Type 'Xxx.DataContracts.WCall' in Assembly 'Xxx.DataContract, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
at Xxx.Notification.NotificationMessageFactory.CreateMessage(NotificationTypeKey notificationTypeKey, NotificationData notificationData) in Xxx.Notification\NotificationCenter.cs:line 36

Si je mets de la Serializable drapeau avant la DataContract on ne résout pas le problème.


merci pour la réponse rapide.
Désolé que j'ai oublié de mettre le code de la NotificationData (édité dans le poste principal)

J'ai essayé de mettre l'attribut Serializable de classe à la fois, sans succès 🙁

#region NotificationData
///<summary>
///Basic class used in the notification service
///</summary>
[Serializable]
[DataContract]
public class NotificationData
{
}
#endregion

et

[Serializable]
public class WCallUpdate : NotificationData
{
private string m_from = "";
[DataMember]
public string From
{
get { return m_from; }
set { m_from = value; }
}
private WCall m_wCall = new WCall();
[DataMember]
public WCall Call
{
get { return m_wCall; }
set { m_wCall = value; }
}
}

**Edit: ** Mea culpa après tout 🙂 Vous étiez tous les deux à droite.
J'ai oublié de propagation de la [Serializable] attribuer à l'ensemble de la classe enfant.
Après la mise à jour et de la compilation, j'ai eu non plus l'exception.
merci à vous deux pour vos réponses 🙂


@Marc Gravier:
En fait j'ai pensé à ce que vous suggérez, et créé le DataContractSerializer, mais je ne suis pas sûr que cela va fonctionner? Comme mes classes à utiliser d'autres classes? le gros problème avec le DataContractSerializer est que vous avez besoin de spécifier le type de l'objet à sérialiser et que ma classe utilise une autre classe que les champs privés, qui pourrait causer un problème de droit?

#region DataContractSerializer
///<summary>
///Creates a Data Contract Serializer for the provided type. The type must be marked with
///the data contract attribute to be serialized successfully.
///</summary>
///<typeparam name="T">The type to be serialized</typeparam>
///<returns>A data contract serializer</returns>
public static DataContractSerializer CreateDataContractSerializer<T>() where T : class
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
return serializer;
}
#endregion
Je suis très confus pourquoi vous utilisez BinaryFormatter avec un contrat (ce commentaire maintenant élargi en une réponse).

OriginalL'auteur srodriguez | 2009-04-16