Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Faut-il appeller Dispose() dans des classes qui contient d'autres classes ?

5 réponses
Avatar
Gilles TOURREAU
Bonjour tout le monde !

Je développe actuellement une classe qui contient des variables membres
privées de type IDisposable.

Faut-il dans cette classe ajouter l'implémentation de l'interface
IDisposable() et appeller Dispose() pour toutes les variables membres ?

Exemple :

public class MaClasse : IDisposable
{
private UneClasseIDisposable classe1;
private UneClasseIDisposable2 classe2;

public virtual void Dispose()
{
if (classe1 != null)
classe1.Dispose();

if (classe2 != null)
classe2.Dispose();
}
}

Est-ce correct ?

Une autre question complémentaire :
Faut-il mettre null dans les variables que l'on "Dispose".

Exemple :

if (classe2 != null)
{
classe2.Dispose();
classe2 = null;
}

En vous remerciant par avance de vos lumières !

--
Gilles TOURREAU
Responsable informatique
gilles.tourreau@pos.fr

Société P.O.S
Spécialiste en motoculture depuis + de 30 ans !
http://www.pos.fr

5 réponses

Avatar
Mehdi
On Sun, 02 Jul 2006 11:52:53 +0200, Gilles TOURREAU wrote:

Bonjour tout le monde !

Je développe actuellement une classe qui contient des variables membres
privées de type IDisposable.

Faut-il dans cette classe ajouter l'implémentation de l'interface
IDisposable() et appeller Dispose() pour toutes les variables membres ?



Oui. Toute instance d'une classe implémentant IDisposable doit etre
"disposée" des qu'elle n'est plus utilisée. Dans le cas ou cette instance
est une variable membre d'un object, elle doit etre "disposée" lorsque son
objet parent n'est plus utile. Le pattern permettant de faire ca en .NET
est le Dispoable Pattern.

public class MaClasse : IDisposable
{
private UneClasseIDisposable classe1;
private UneClasseIDisposable2 classe2;

public virtual void Dispose()
{
if (classe1 != null)
classe1.Dispose();

if (classe2 != null)
classe2.Dispose();
}
}

Est-ce correct ?



Oui

Une autre question complémentaire :
Faut-il mettre null dans les variables que l'on "Dispose".



En général non, ce n'est pas utile. Cela peux etre utile si
- l'objet disposé utilise beaucoup de mémoire et
- l'objet disposé est une variable locale a une fonction et
- l'objet disposé est disposé au beau milieu de cette fonction et
- cette fonction va avoir besoin d'allouer de la memoire apres que l'objet
soit disposé

Dans ce cas, le mettre a null permettra au GC de se rendre compte que plus
personne ne référence cet object ce qui lui permettra de libérer la mémoire
utilisé par cet objet dans le cas ou la reste de la fonction en question a
besoin de plus de mémoire qu'il n'y a de disponible. Ce genre de situation
est tres tres rare cela dit. Rien ne t'empeche cependant de mettre tes
variables a null si tu le souhaite.
Avatar
Simon Mourier [SoftFluent]
Le null ne sert à rien ici par rapport au GC puisque les instances de
classe1 et classe2 sont liés à l'instance de MaClasse. Si une instance de
MaClasse va dans le GC, les instances classe1 et class2 aussi. Que les
références aux instances classe1 et classe2 au sein de la référence de
l'instance de Maclasse soient nulles ou pas ne change rien du tout.

Mettre les variables à null peut en revanche parfois servir à marquer le
fait que les objets ont été disposés pour éviter de passer deux fois au même
endroit, mais ça n'a rien à voir avec la gestion de la mémoire.

Simon.
www.softfluent.com


"Mehdi" a écrit dans le message de news:
1mupte4czirfm$.1rjzkp23ju0n2$
On Sun, 02 Jul 2006 11:52:53 +0200, Gilles TOURREAU wrote:

Bonjour tout le monde !

Je développe actuellement une classe qui contient des variables membres
privées de type IDisposable.

Faut-il dans cette classe ajouter l'implémentation de l'interface
IDisposable() et appeller Dispose() pour toutes les variables membres ?



Oui. Toute instance d'une classe implémentant IDisposable doit etre
"disposée" des qu'elle n'est plus utilisée. Dans le cas ou cette instance
est une variable membre d'un object, elle doit etre "disposée" lorsque son
objet parent n'est plus utile. Le pattern permettant de faire ca en .NET
est le Dispoable Pattern.

public class MaClasse : IDisposable
{
private UneClasseIDisposable classe1;
private UneClasseIDisposable2 classe2;

public virtual void Dispose()
{
if (classe1 != null)
classe1.Dispose();

if (classe2 != null)
classe2.Dispose();
}
}

Est-ce correct ?



Oui

Une autre question complémentaire :
Faut-il mettre null dans les variables que l'on "Dispose".



En général non, ce n'est pas utile. Cela peux etre utile si
- l'objet disposé utilise beaucoup de mémoire et
- l'objet disposé est une variable locale a une fonction et
- l'objet disposé est disposé au beau milieu de cette fonction et
- cette fonction va avoir besoin d'allouer de la memoire apres que l'objet
soit disposé

Dans ce cas, le mettre a null permettra au GC de se rendre compte que plus
personne ne référence cet object ce qui lui permettra de libérer la
mémoire
utilisé par cet objet dans le cas ou la reste de la fonction en question a
besoin de plus de mémoire qu'il n'y a de disponible. Ce genre de situation
est tres tres rare cela dit. Rien ne t'empeche cependant de mettre tes
variables a null si tu le souhaite.


Avatar
Laurent
bonjour,
on m'a conseillé, en formation c# 2, de laisser le GC faire son travail,
donc de ne pas appeler le Dispose.
l'explication, si je me souviens bien (ca fait 1 an !!!) : le fait de faire
un dispose appel et force le GC, si on ne le fait pas (le dispose), l'objet
est quand meme purger par le GC mais quand, ca on ne sait pas.

le principe est le suivant : le GC passe et si il voit un objet qui n'est
plus lié à rien, il le purge et ainsi de suite. dans ton cas, tu as un objet
(A) qui en contient d'autre (B et C) : donc si casse le lien de ton objet A,
le GC va le purger, et lors du passage suivant, il purgera les objets B et C
et ainsi de suite.

on m'avait conseillé de ne pas faire les dispose car d'une manière générale,
ca chamboulé l'organisation du GC, mais bon si c'est comme le DoEvents en
VB6... y' a des fois ou tu as pas le choix.

moralité : fait le seulement si le comportement "automatique" tu GC ne te
convient pas et que tu dois purger la mémoire sans attendre.

--
Laurent M.
Développeur .NET


"Gilles TOURREAU" a écrit :

Bonjour tout le monde !

Je développe actuellement une classe qui contient des variables membres
privées de type IDisposable.

Faut-il dans cette classe ajouter l'implémentation de l'interface
IDisposable() et appeller Dispose() pour toutes les variables membres ?

Exemple :

public class MaClasse : IDisposable
{
private UneClasseIDisposable classe1;
private UneClasseIDisposable2 classe2;

public virtual void Dispose()
{
if (classe1 != null)
classe1.Dispose();

if (classe2 != null)
classe2.Dispose();
}
}

Est-ce correct ?

Une autre question complémentaire :
Faut-il mettre null dans les variables que l'on "Dispose".

Exemple :

if (classe2 != null)
{
classe2.Dispose();
classe2 = null;
}

En vous remerciant par avance de vos lumières !

--
Gilles TOURREAU
Responsable informatique


Société P.O.S
Spécialiste en motoculture depuis + de 30 ans !
http://www.pos.fr





Avatar
Mehdi
On Mon, 17 Jul 2006 02:47:01 -0700, Laurent wrote:

on m'a conseillé, en formation c# 2, de laisser le GC faire son travail,
donc de ne pas appeler le Dispose.
l'explication, si je me souviens bien (ca fait 1 an !!!) : le fait de faire
un dispose appel et force le GC,



Je pense que tu confond avec GC.Collect(). Appeler Dispose() ne fait
qu'executer la méthode Dispose(), n'a strictement rien a voir avec le GC et
ne force absoument pas le GC a rentrer en action. Une fois Dispose()
appelé, l'objet est toujours la en mémoire et sera purgé plus tard par le
GC lorsqu'il se sentira d'humeur a le faire.

si on ne le fait pas (le dispose), l'objet
est quand meme purger par le GC mais quand, ca on ne sait pas.



Meme si on appele Dispose(), l'objet est purgé plus tard par le GC et on ne
sait pas quand.

le principe est le suivant : le GC passe et si il voit un objet qui n'est
plus lié à rien, il le purge et ainsi de suite. dans ton cas, tu as un objet
(A) qui en contient d'autre (B et C) : donc si casse le lien de ton objet A,
le GC va le purger, et lors du passage suivant, il purgera les objets B et C
et ainsi de suite.



Oui. Mais il y a un probleme pour les objet contenant des ressources
non-managées (des Handles crée via P/Invoke, une connection vers une base
de donnée, un fichier ouvert...). Le GC ne s'occupe que de la mémoire et ne
sais pas comment libérer ces ressources. Les classes contenant des
ressources non-managées doivent donc implémenter un Finalizer qui s'occupe
de libérer ces ressources. Lorsque le GC passe, si il voit que l'objet a un
Finalizer, il l'appele d'abord avant de supprimer l'objet. Ce mécanisme
permet d'éviter des fuites de ressources.

Seulement, comme tu l'as dit au dessus, le GC peux prendre son temps avant
de passer et conserver une ressource non-managée dont on n'a plus besoin
pendant un temps potentiellement tres long est généralement une tres
mauvaise idée. Donc ces ressources doivent etre libérées des que possible
sans attendre le GC. D'ou l'idée de la méthode Dispose(). La méthode
Dispose() est la pour permettre a l'utilisateur d'indiquer a un objet qu'il
n'a plus besoin de lui et que l'objet doit libérer ces ressoures
non-managées immédiatement. En général la méthode Dispose(), en plus de
libérer les ressources non-managées, supprime également le Finalizer, qui
n'est plus nécéssaire vu que les ressources non-managées ont déja été
libérer, avec GC.SuppressFinalize(). Cela permet au GC de faire son boulot
plus rapidement vu qu'il n'aura pas a appeler le finalizer pour cet objet.
Dans le cas ou l'utilisateur a oublié d'appeler Dispose(), le Finalizer
n'aura pas été supprimé et sera donc appelé par le GC lorsqu'il passera
permettant ainsi de libérer toutes les ressources non-managées.

on m'avait conseillé de ne pas faire les dispose car d'une manière générale,
ca chamboulé l'organisation du GC,



Si on t'a vraiment conseillé de ne jamais implémenter ou appeler un
Dispose() quelque soit la situation, alors j'espere que tu n'a pas payé
trop cher pour ta formation car, tres clairement, le formateur n'y
connaissait strictement rien en .NET. Mais, comme dit au dessus, je pense
que tu confond en fait avec GC.Collect() qui est effectivement une méthode
a ne jamais appeler sauf situation vraiment exceptionnelle.
Avatar
Laurent
tu as très surement raison, mais bon comme j'ai di, ca fait 1 an que j'ai
fait la formation et ca fait seulement 1an que je fais de l'objet, et du .net
désolé pour mes lacunes et merci à toi de les combler, surtout pour Gilles !

j'essaierai de dire moins de conneries la prochaine fois (!!!)

sinon pour la formation on la payé assez cher, donc j'ai surement confondu !
lol

@+

--
Laurent M.
Développeur .NET


"Mehdi" a écrit :

On Mon, 17 Jul 2006 02:47:01 -0700, Laurent wrote:

> on m'a conseillé, en formation c# 2, de laisser le GC faire son travail,
> donc de ne pas appeler le Dispose.
> l'explication, si je me souviens bien (ca fait 1 an !!!) : le fait de faire
> un dispose appel et force le GC,

Je pense que tu confond avec GC.Collect(). Appeler Dispose() ne fait
qu'executer la méthode Dispose(), n'a strictement rien a voir avec le GC et
ne force absoument pas le GC a rentrer en action. Une fois Dispose()
appelé, l'objet est toujours la en mémoire et sera purgé plus tard par le
GC lorsqu'il se sentira d'humeur a le faire.

> si on ne le fait pas (le dispose), l'objet
> est quand meme purger par le GC mais quand, ca on ne sait pas.

Meme si on appele Dispose(), l'objet est purgé plus tard par le GC et on ne
sait pas quand.

> le principe est le suivant : le GC passe et si il voit un objet qui n'est
> plus lié à rien, il le purge et ainsi de suite. dans ton cas, tu as un objet
> (A) qui en contient d'autre (B et C) : donc si casse le lien de ton objet A,
> le GC va le purger, et lors du passage suivant, il purgera les objets B et C
> et ainsi de suite.

Oui. Mais il y a un probleme pour les objet contenant des ressources
non-managées (des Handles crée via P/Invoke, une connection vers une base
de donnée, un fichier ouvert...). Le GC ne s'occupe que de la mémoire et ne
sais pas comment libérer ces ressources. Les classes contenant des
ressources non-managées doivent donc implémenter un Finalizer qui s'occupe
de libérer ces ressources. Lorsque le GC passe, si il voit que l'objet a un
Finalizer, il l'appele d'abord avant de supprimer l'objet. Ce mécanisme
permet d'éviter des fuites de ressources.

Seulement, comme tu l'as dit au dessus, le GC peux prendre son temps avant
de passer et conserver une ressource non-managée dont on n'a plus besoin
pendant un temps potentiellement tres long est généralement une tres
mauvaise idée. Donc ces ressources doivent etre libérées des que possible
sans attendre le GC. D'ou l'idée de la méthode Dispose(). La méthode
Dispose() est la pour permettre a l'utilisateur d'indiquer a un objet qu'il
n'a plus besoin de lui et que l'objet doit libérer ces ressoures
non-managées immédiatement. En général la méthode Dispose(), en plus de
libérer les ressources non-managées, supprime également le Finalizer, qui
n'est plus nécéssaire vu que les ressources non-managées ont déja été
libérer, avec GC.SuppressFinalize(). Cela permet au GC de faire son boulot
plus rapidement vu qu'il n'aura pas a appeler le finalizer pour cet objet.
Dans le cas ou l'utilisateur a oublié d'appeler Dispose(), le Finalizer
n'aura pas été supprimé et sera donc appelé par le GC lorsqu'il passera
permettant ainsi de libérer toutes les ressources non-managées.

> on m'avait conseillé de ne pas faire les dispose car d'une manière générale,
> ca chamboulé l'organisation du GC,

Si on t'a vraiment conseillé de ne jamais implémenter ou appeler un
Dispose() quelque soit la situation, alors j'espere que tu n'a pas payé
trop cher pour ta formation car, tres clairement, le formateur n'y
connaissait strictement rien en .NET. Mais, comme dit au dessus, je pense
que tu confond en fait avec GC.Collect() qui est effectivement une méthode
a ne jamais appeler sauf situation vraiment exceptionnelle.