[C#] Destruction d'objets ? [Résolu]

Destruction d'objets ? [Résolu] [C#] - C#/.NET managed - Programmation

Marsh Posté le 13-04-2005 à 10:04:30    

Bonjour,
 
Je fais une application utilisant plusieurs fenêtres. Dans une Form A j'instancie une Form B lorsque l'utilisateur clique sur un bouton, et je ne veut qu'une instance de ma classe B.
 
class A:Form{
B b;
...
}
 
Je ne suis pas vraiment familiarisé avec la destruction d'objets en C# mais lorsque je ferme la Form B (bouton fermeture), il y a appel à b.Close(); et implicitement b.Dispose();.  
 
Pour moi à ce stade A.b devrait être détruit !
 
Mais A.b n'est pas à null... Et j'ai toujours accès aux variables de b (exemple b.text) en lecture et en écriture  
 
En fait mon test b==null devait me permettre de savoir si je devais ouvrir une nouvelle instance de B ou pas. J'ai trouvé une variable qui peut m'aider : b.IsDisposed.  
 
Mais là j'ai eu encore une surprise : l'appel à b.Close(); implique l'appel à b.Dispose(); si b est visible mais pas si b est caché ...  
 
Là je n'y comprends plus rien ! Il me semblait que l'appel à b.Close(); impliquait systématiquement l'appel à b.Dispose();  
 
 
Pourquoi l'accès à b.Text ne lève pas d'exception et pourquoi A.b n'est pas à null.
Si quelqu'un peut m'expliquer les méchanismes de destruction en C# ou me donner un lien, ce serai sympa.
 
Gaxx


Message édité par Gaxx le 13-04-2005 à 11:54:11
Reply

Marsh Posté le 13-04-2005 à 10:04:30   

Reply

Marsh Posté le 13-04-2005 à 10:09:48    

Parce que la méthode Dispose de l'interface IDisposable ne sert qu'a libérer les ressources utilisées par une classe. En général, ça ne sert QUE pour libérer les ressources non-managées. En pratique, on liberera aussi les membres qui implémentent IDisposable.  
 
Sinon tu peux manuellement mettre b à null, vu que Dispose ne le fait pas. Enfin, pour l'histoire du Close, c'est en général plus logique d'appeller Close que Dispose sur certains objets, alors Microsoft préconise d'implémenter une méthode Close qui fait directement appel à Dispose

Reply

Marsh Posté le 13-04-2005 à 10:40:48    

FlorentG a écrit :

Parce que la méthode Dispose de l'interface IDisposable ne sert qu'a libérer les ressources utilisées par une classe. En général, ça ne sert QUE pour libérer les ressources non-managées. En pratique, on liberera aussi les membres qui implémentent IDisposable.


 
J'avais lu quelque chose allant dans ce sens mais je ne suis pas sûr de la méthode...
Si je comprend bien, dans mathode Dicpose) de la classe en cours de fermeture il faut appeler la méthode Dispose pour chaque membre implémentant IDisposable ?
Et de même lorsque je cesse d'utiliser un objet (implémentant IDisposable) pour le remplacer par un autre, je dois appeler Dispose là aussi ?  
 

FlorentG a écrit :

Sinon tu peux manuellement mettre b à null, vu que Dispose ne le fait pas. Enfin, pour l'histoire du Close, c'est en général plus logique d'appeller Close que Dispose sur certains objets, alors Microsoft préconise d'implémenter une méthode Close qui fait directement appel à Dispose


Mais il y a un hic dans le comportement de C# : pourquoi lorsque ma Form b est visible Close appelle Dispose et ne le fait pas lorsque b est caché via b.Hide(); ???
J'ai contourné la fifficulté en utilisant b.IsDisposed en appelant manuellement b.Dispose() lors de la fermeture...
 

Reply

Marsh Posté le 13-04-2005 à 10:48:25    

Gaxx a écrit :

J'avais lu quelque chose allant dans ce sens mais je ne suis pas sûr de la méthode...
Si je comprend bien, dans mathode Dicpose) de la classe en cours de fermeture il faut appeler la méthode Dispose pour chaque membre implémentant IDisposable ?
Et de même lorsque je cesse d'utiliser un objet (implémentant IDisposable) pour le remplacer par un autre, je dois appeler Dispose là aussi ?


:jap: Si tu n'appelle pas Dispose, alors certaines ressources non-managées ne seront pas explicitement libérées. Ca veut dire qu'elles seront libérées via le Finalizer, ce qui est à chier.
 
 

Gaxx a écrit :

Mais il y a un hic dans le comportement de C# : pourquoi lorsque ma Form b est visible Close appelle Dispose et ne le fait pas lorsque b est caché via b.Hide(); ???
J'ai contourné la fifficulté en utilisant b.IsDisposed en appelant manuellement b.Dispose() lors de la fermeture...


Qui dis Hide dis Show :D Donc quand tu la planques, ça veut peut-être dire que tu veux la réafficher plus tard, donc on ne la Dispose pas

Reply

Marsh Posté le 13-04-2005 à 10:59:02    

FlorentG a écrit :

:jap: Si tu n'appelle pas Dispose, alors certaines ressources non-managées ne seront pas explicitement libérées. Ca veut dire qu'elles seront libérées via le Finalizer, ce qui est à chier.


 
C'est noté... Mais il va falloir que je vérifie toutes mes classes ...  :cry:  
 

FlorentG a écrit :

Qui dis Hide dis Show :D Donc quand tu la planques, ça veut peut-être dire que tu veux la réafficher plus tard, donc on ne la Dispose pas


Vi tant qu'on ne la ferme pas ok, mais si on ferme un objet caché c'est qu'on en a plus besoin...  
En fait c'est ma fenêtre de loggin qui me sert de références pour connaître l'utilisateur, les chemins de bdd, ... Donc après validation je le garde ouverte mais cachée  :whistle:  
Et lorsque l'utilisateur veut se déconnecter je ferme toutes les fenêtres via la méthode Close.
 
Je pense que la bas de mon problème est que je n'ai pas fait de programmation purement objet et mes fonction métier sont dans mes classes Form...  
 :o Je prend le devant des critiques : je sais que c'est pas bien  ;)

Reply

Marsh Posté le 13-04-2005 à 11:04:15    

En fait la méthode Close n'appel pas directement la méthode Dispose :

public void Close()
{
      if (base.GetState(0x40000))
      {
            object[] objArray1 = new object[1] { "Close" } ;
            throw new InvalidOperationException(SR.GetString("ClosingWhileCreatingHandle", objArray1));
      }
      if (base.IsHandleCreated)
      {
            base.SendMessage(0x10, 0, 0);
      }
}


Donc quand tu voyage dans les méandres du truc, ça passe par des messages, des vérifs d'états, etc... Donc faut appeller dispose manuellement

Reply

Marsh Posté le 13-04-2005 à 11:11:20    

Un petit pâté de NRaynaud :

nraynaud a écrit :

il n'existe pas de destruction en C#, mais une finalisation.  
 
S'il n'existe plus aucune référence vers un objet, celui-ci est récupéré par le système pour en libérer la mémoire.  
 
D'autre part, en C#, et c'est assez malin, le cycle de vie des objet est fixé par convention : création -> initialize() open()->travail réel->close()->open()->re-travail->close()->Dispose()->finalisation.  
 
la création (new) et la finalisation (~Machin) sont des opération de gestion de mémoire.  
initialize() et Dispose() sont des opérations qui ne peuvent être appellées qu'une fois dans la vie de l'objet.  
 
open() et close() sont des opérations classiques qui normalement peuvent être appellées plusieurs fois (ouvrir, travail fermer, ouvrir, travail fermer etc.)  
 
il est évident que si un objet n'a pas *absolument* besoin de toutes ses opérations, il faut éviter de lui en mettre, car avec ces opérations, le nombre d'états possible de l'objet est grand, ce qui rend les choses plus confuses et la maintenance plus difficile.  
 
 
Après ce petit rappel, il est évident qu'aucune de ces méthodes ne va aller toucher un pointeur sur l'objet ailleur en mémoire, après le Dispose(), l'objet reste en mémoire tant qu'il reste des pointeurs sur lui dans la mémoire. Il faut les mettre à null explicitement à la main.  
 
Tout ceci est en rapport avec les hiérarchies de composition, par exemple, lorsqu'un composant (j'utilise ce terme plus abstrait qu'objet volontairement) "entre" dans son environnement de travail, il va probablement recevoir un message pour l'alerter, c'est à ce moment qu'il va effectuer son open() et prévenir ses sous-composants. A la sortie, c'est le close() qui va être appellé.


Reply

Marsh Posté le 13-04-2005 à 11:12:59    

Enfin après ça dépend si l'objet peut être 'résurrecté', donc être réutilisé après un Dispose.

Reply

Marsh Posté le 13-04-2005 à 11:53:54    

FlorentG a écrit :

Enfin après ça dépend si l'objet peut être 'résurrecté', donc être réutilisé après un Dispose.


 
Le dispose doit empécher la réutilisation :

Citation :

initialize() et Dispose() sont des opérations qui ne peuvent être appellées qu'une fois dans la vie de l'objet.


Maintenant je comprend pourquoi l'objet était toujours accessible.
 
Merci pour toutes les infos.

Reply

Marsh Posté le 13-04-2005 à 12:01:49    

Presque :

Citation :

Si la méthode Dispose d'un objet est appelée plus d'une fois, l'objet doit ignorer tous les appels autres que le premier.


Mais on peut faire aussi des objets qui reviennent à la vie après un dispose

Reply

Marsh Posté le 13-04-2005 à 12:01:49   

Reply

Marsh Posté le 13-04-2005 à 12:13:10    

FlorentG a écrit :

Presque :

Citation :

Si la méthode Dispose d'un objet est appelée plus d'une fois, l'objet doit ignorer tous les appels autres que le premier.


Mais on peut faire aussi des objets qui reviennent à la vie après un dispose


 
 
 [:anshi] Je ne veut pas de zombis dans mon appli moi ...
Open et Close ne font que de l'allocation et de la désallocation de variables managées.
Dispose place l'objet dans le garbage collector, et donc on peut le sortir de son cercueil.  
Et l'appel à Finalize détruit complètement l'objet.
C'est bien ça ?

Reply

Marsh Posté le 13-04-2005 à 13:41:43    

Finalize est appelé automatiquement par le GC. Ce qui est merdique. Si t'as un objet qui contient des ressources non managées, et que t'appelle pas dispose, alors ces ressources vont survire au moins une garbage collection, puis enfin le GC va appeler Finalize. Donc ça garde des objets en mémoire alors que ça devrait pas, etc. Donc t'as interêt à toujours utiliser la méthode Dispose, ce qui, en général, supprime la finalization.
Pour ce qui est de Open et Close, ça dépend de l'objet. Certaines classes, dans leur méthode Close, ne font pas appel à dispose :(

Reply

Marsh Posté le 13-04-2005 à 15:56:19    

Florentg > j'ai expliqué pourquoi, il faut que les objets re-ouvrable puissent survivre.


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 13-04-2005 à 15:56:34    

Effectivement :jap:

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed