Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1425 connectés 

  FORUM HardWare.fr
  Programmation
  C#/.NET managed

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

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

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

n°1045397
Gaxx
Posté le 13-04-2005 à 10:04:30  profilanswer
 

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
mood
Publicité
Posté le 13-04-2005 à 10:04:30  profilanswer
 

n°1045408
FlorentG
Unité de Masse
Posté le 13-04-2005 à 10:09:48  profilanswer
 

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

n°1045440
Gaxx
Posté le 13-04-2005 à 10:40:48  profilanswer
 

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...
 

n°1045450
FlorentG
Unité de Masse
Posté le 13-04-2005 à 10:48:25  profilanswer
 

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

n°1045474
Gaxx
Posté le 13-04-2005 à 10:59:02  profilanswer
 

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  ;)

n°1045491
FlorentG
Unité de Masse
Posté le 13-04-2005 à 11:04:15  profilanswer
 

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

n°1045510
FlorentG
Unité de Masse
Posté le 13-04-2005 à 11:11:20  profilanswer
 

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é.


n°1045513
FlorentG
Unité de Masse
Posté le 13-04-2005 à 11:12:59  profilanswer
 

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

n°1045621
Gaxx
Posté le 13-04-2005 à 11:53:54  profilanswer
 

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.

n°1045632
FlorentG
Unité de Masse
Posté le 13-04-2005 à 12:01:49  profilanswer
 

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

mood
Publicité
Posté le 13-04-2005 à 12:01:49  profilanswer
 

n°1045660
Gaxx
Posté le 13-04-2005 à 12:13:10  profilanswer
 

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 ?

n°1045759
FlorentG
Unité de Masse
Posté le 13-04-2005 à 13:41:43  profilanswer
 

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 :(

n°1046046
nraynaud
lol
Posté le 13-04-2005 à 15:56:19  profilanswer
 

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


---------------
trainoo.com, c'est fini
n°1046047
FlorentG
Unité de Masse
Posté le 13-04-2005 à 15:56:34  profilanswer
 

Effectivement :jap:


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C#/.NET managed

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

 

Sujets relatifs
[RESOLU] bizarrerie avec file_existsgenerer captcha et verifier saisie dans formulaire [RESOLU]
Débutant C++ - Intéractions d'objets de même nomBug bizarre [résolu]
[RESOLU] Pb d'affichage avec plusieurs éléments[HTML] probleme de lien image[resolu]
Log -> PHP -> Mysql | Coment faire ? [Résolu][java] clone() [partielement resolu]
Rectangles pleins - [RESOLU]comment mettre un lien sur un bouton flash ??? [Résolu]
Plus de sujets relatifs à : [C#] Destruction d'objets ? [Résolu]


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR