IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Modifier un Dictionary durant la désérialisation [Débutant]


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 3
    Par défaut Modifier un Dictionary durant la désérialisation
    Bonjour,

    Durant la désérialisation d'un objet, il est nécessaire que j'ajoute des éléments dans un de ses membres de type Dictionary.

    Je procède comme suit dans le constructeur :
    - je désérialise le Dictionary à partir des informations de sérialisation.
    - j'ajoute un élément

    Une exception est levée à ce moment dans

    System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)

    En examinant l'état du Dictionary, je constate qu'après sa désérialisation, la propriété Count est égale à zéro alors qu'un certain nombre d'éléments devraient déjà s'y trouver.

    Si je laisse se dérouler normalement la désérialisation, sans tenter d'ajouter un élément, le Dictionary est complet, on y retrouve son contenu original.

    J'en conclu que le Dictionary se trouve dans un état "bloqué" tant que la désérialisation n'est pas terminée.

    J'ai pensé à implémenter l'interface IDeserializationCallback, mais c'est exactement la même exception qui est levée.

    Est-il incorrect de ma part de procéder comme je le fais ?
    Existe-t-il un moyen plus approprié pour réaliser cela ?

    Merci d'avance
    Pierre

    Code utilisé pour la sérialisation et la désérialisation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    			MaClasse m1 = new MaClasse();                            // Instance originale
    			MemoryStream stream = new MemoryStream();                // Flux utilisé pour la sérialisation/désérialisation
    			BinaryFormatter formatter = new BinaryFormatter();       // Formatteur binaire
     
    			formatter.Serialize(stream, m1);                         // Sérialisation de l'objet
     
    			stream.Seek(0, SeekOrigin.Begin);				         // Repositionnement au début du flux
     
    			MaClasse mc2 = (MaClasse) formatter.Deserialize(stream); // Désérialisation dans un nouvel objet
    Classe utilisée pour les tests
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    	[Serializable]
    	public class MaClasse : ISerializable, IDeserializationCallback
    	{
    		// Constructeur par défaut
    		public MaClasse()
    		{
    			// Ajout d'éléments initiaux
    			m_MonDico.Add(0, "0");
    			m_MonDico.Add(1, "1");
    			m_MonDico.Add(2, "2");
    		}
     
    		// Dictionnaire 
    		private Dictionary<int, string> m_MonDico = new Dictionary<int, string>();
     
    		/// <summary>
    		/// Implémentation de l'interface ISerializable
    		/// </summary>
    		#region ISerializable Members
     
    		// Constructeur pour la désérialisation
    		private MaClasse(SerializationInfo info, StreamingContext context)
    		{
    			// Désérialisation du dictionnaire
    			m_MonDico = (Dictionary<int, string>)info.GetValue("MonDico", typeof(Dictionary<int, string>));
     
    			// Ajout d'un élément
    			m_MonDico.Add(8, "8");
    		}
     
    		// Méthode appelée lors de la sérialisation
    		public void GetObjectData(SerializationInfo info, StreamingContext context)
    		{
    			info.AddValue("MonDico", m_MonDico);
    		}
     
    		#endregion
     
    		/// <summary>
    		/// Implémentation de l'interface IDeserializationCallback
    		/// </summary>
    		#region IDeserializationCallback Members
     
    		// Evènement appelé après la désérialisation
    		public void OnDeserialization(object sender)
    		{
    			// Ajout d'un élément
    			m_MonDico.Add(9, "9");
    		}
     
    		#endregion
    	}

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par pi-r-o Voir le message
    Une exception est levée à ce moment dans

    System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
    Citation Envoyé par pi-r-o Voir le message
    J'ai pensé à implémenter l'interface IDeserializationCallback, mais c'est exactement la même exception qui est levée.
    Ce serait quand même plus facile de répondre si tu disais quelle exception...

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 3
    Par défaut
    Oui, désolé pour l'oubli.
    Je n'ai pas mentionné non plus que j'utilisais le framework .NET 2.0.

    Voici le détail de l'exception.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    System.Reflection.TargetInvocationException was unhandled
      Message="Exception has been thrown by the target of an invocation."
      Source="mscorlib"
      StackTrace:
           at System.RuntimeMethodHandle._SerializationInvoke(Object target, SignatureStruct& declaringTypeSig, SerializationInfo info, StreamingContext context)
           at System.Reflection.RuntimeConstructorInfo.SerializationInvoke(Object target, SerializationInfo info, StreamingContext context)
           at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
           at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
           at System.Runtime.Serialization.ObjectManager.DoFixups()
           at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
           at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
           at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
           at CustomDictionaryDeserialization.Form1.button1_Click(Object sender, EventArgs e) in c:\Temp\CustomDictionaryDeserialization\Form1.cs:line 32
           at System.Windows.Forms.Control.OnClick(EventArgs e)
           at System.Windows.Forms.Button.OnClick(EventArgs e)
           at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
           at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
           at System.Windows.Forms.Control.WndProc(Message& m)
           at System.Windows.Forms.ButtonBase.WndProc(Message& m)
           at System.Windows.Forms.Button.WndProc(Message& m)
           at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
           at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
           at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
           at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
           at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
           at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
           at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
           at System.Windows.Forms.Application.Run(Form mainForm)
           at CustomDictionaryDeserialization.Program.Main() in c:\Temp\CustomDictionaryDeserialization\Program.cs:line 17
           at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()
    La propriété InnerException est de type System.NullReferenceException
    Object reference not set to an instance of an object.
    Elle survient dans mscorlib. Voici la pile d'appels:

    at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
    at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
    at CustomDictionaryDeserialization.MaClasse..ctor(SerializationInfo info, StreamingContext context) in c:\Temp\CustomDictionaryDeserialization\MyClass.cs:line 35
    Voici le détail de l'exception levée en accédant au Dictionary depuis la méthode OnDeserialization.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    System.NullReferenceException was unhandled
      Message="Object reference not set to an instance of an object."
      Source="mscorlib"
      StackTrace:
           at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
           at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
           at CustomDictionaryDeserialization.MaClasse.OnDeserialization(Object sender) in c:\Temp\CustomDictionaryDeserialization\MyClass.cs:line 55
           at System.Runtime.Serialization.DeserializationEventHandler.Invoke(Object sender)
           at System.Runtime.Serialization.ObjectManager.RaiseDeserializationEvent()
           at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
           at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
           at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
           at CustomDictionaryDeserialization.Form1.button1_Click(Object sender, EventArgs e) in c:\Temp\CustomDictionaryDeserialization\Form1.cs:line 32
           at System.Windows.Forms.Control.OnClick(EventArgs e)
           at System.Windows.Forms.Button.OnClick(EventArgs e)
           at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
           at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
           at System.Windows.Forms.Control.WndProc(Message& m)
           at System.Windows.Forms.ButtonBase.WndProc(Message& m)
           at System.Windows.Forms.Button.WndProc(Message& m)
           at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
           at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
           at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
           at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
           at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
           at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
           at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
           at System.Windows.Forms.Application.Run(Form mainForm)
           at CustomDictionaryDeserialization.Program.Main() in c:\Temp\CustomDictionaryDeserialization\Program.cs:line 17
           at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()
    Pierre

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Effectivement, je reproduis le problème chez moi... très bizarre.

    En fait j'ai l'impression que info.GetValue renvoie un objet qui est instancié mais pas encore désérialisé (un objet "vide" quoi...) : tous les champs du dictionnaire récupéré sont à 0 ou null... Par contre, après que la désérialisation soit complètement terminée, le dictionnaire est correctement initialisé et tu peux lui ajouter des éléments. En fait je crois que ton scénario d'utilisation n'est tout simplement pas supporté...

    Tu peux "tricher" en appelant m_MonDico.OnDeserialize à partir de MaClasse.OnDeserialize, ça semble résoudre le problème. Mais à mon avis c'est un peu de la bidouille, il vaudrait mieux pas essayer de modifier le dico pendant la désérialisation.

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 3
    Par défaut
    Je vais suivre ton conseil et éviter la bidouille.

    Comme la sérialisation est totalement gérée dans la classe, je vais utiliser un drapeau non sérialisé qui indiquera après la désérialisation s'il y a lieu de compléter le dictionnaire. C'est un peu du bricolage aussi, mais moins risqué

    Un tout grand merci pour le coup de main !

    Pierre

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XL-2013] Modifier cellule manuellement durant exécution d'une macro
    Par oieretxe dans le forum Macros et VBA Excel
    Réponses: 11
    Dernier message: 10/01/2014, 00h25
  2. Modifier un resourcestring durant l'exécution
    Par arobasseb dans le forum Langage
    Réponses: 2
    Dernier message: 02/02/2010, 21h32
  3. Modifier un paramètre durant la simulation
    Par Frozenbrain dans le forum Simulink
    Réponses: 2
    Dernier message: 14/11/2007, 18h07
  4. Modifier une cellule d'une GridView durant l'update
    Par harry25 dans le forum VB.NET
    Réponses: 1
    Dernier message: 26/04/2007, 11h16
  5. Réponses: 4
    Dernier message: 19/02/2006, 17h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo