Disposer vs disposer (bool)
Je suis confus au sujet de disposer. J'essaie d'obtenir mon code en disposant correctement les ressources. J'ai donc configuré mes classes comme IDisposable (avec une méthode Dispose) en m'assurant que la méthode Dispose est appelée.
Mais maintenant FXCop me dit beaucoup de choses sur Disposing = false et appelle Dispose (false).
Je ne vois pas une méthode Dispose qui prend un bool. Dois-je le faire? Si oui, pourquoi? Pourquoi ne pas simplement avoir une méthode qui est appelée quand elle se débarrasse?
En outre, la ligne dont se plaint FXCop est la suivante:
~OwnerDrawnPanel()
{
_font.Dispose();
}
, Il dit:
CA1063: Microsoft.Conception: Modifier ' OwnerDrawnPanel.~OwnerDrawnPanel () ' pour qu'il appelle dispose(false), puis renvoie.
Mais la police n'a pas de Dispose (bool) dessus (que je peux trouver).
Pour résumer:
Pourquoi ai-je besoin D'un disposer (bool)? et si je le fais, pourquoi la police ne l'a-t-elle pas? et comme il ne l'a pas, pourquoi FxCop me demande-t-il de l'utiliser?
Merci pour toutes les bonnes réponses. Je crois que je comprends maintenant. Voici
La réponse telle que je la vois:
L'élimination des ressources "non gérées" se divise en deux catégories:
- ressources qui sont encapsulées dans une classe gérée (c'est-à-dire Bitmap, police, etc.), mais qui doivent encore être appelées pour les nettoyer correctement.
- les ressources que vous avez allouées, qui sont des représentations de ressources natives (c'est-à-dire des contextes de périphériques qui doivent être libérés)
Dispose(bool) est utilisé pour indiquer la différence entre les deux:
- lorsque Dispose est directement appelé sur votre objet, vous voulez libérer les deux types de " non gérés" ressources.
- lorsque votre objet est prêt pour la récupération de place, vous n'avez pas à vous soucier du premier type de ressources. Le garbage collector prendra soin d'eux quand il les nettoie. Vous n'avez qu'à vous soucier des vraies ressources natives que vous avez allouées (le cas échéant).
10 réponses
IDisposable
fournit une méthode avec la signature
public void Dispose()
Meilleures pratiques Microsoft ( http://msdn.microsoft.com/en-us/library/fs2xkftw.aspx ) recommande de faire une deuxième méthode privée avec la signature
private void Dispose(bool)
Votre méthode de disposition publique et Finalizer doivent appeler cette méthode de disposition privée pour éviter de disposer plusieurs fois des ressources gérées.
Vous pouvez corriger l'avertissement que vous recevez en implémentant IDisposable et en éliminant votre objet font dans la méthode dispose, ou la création d'une méthode Dispose(bool)
dans votre classe, et faire votre finalizer appeler cette méthode.
Dispose(bool)
est un modèle à implémenter Finalize
et Dispose
pour nettoyer les ressources non gérées, voir ceci pour plus de détails
Dispose(bool)
n'est pas destiné à être public, et c'est pourquoi vous ne le voyez pas sur Font
.
Dans le cas où un utilisateur de votre classe oublie d'appeler Dispose sur votre méthode, vous libérerez les ressources non gérées seulement en faisant un appel à Dispose(false)
dans le Finalizer
.
Dans le cas où IDispose est appelé correctement, vous appelez le Dispose sur les ressources gérées et aussi Prenez soin des ressources non gérées.
Le drapeau est de distinguer les deux cas.
C'est un modèle recommandé par MSDN.
FxCop dit que vous devez implémenter le modèle jetable comme décrit ici . Notez que vous devriez Pas utiliser des finaliseurs pour disposer des ressources gérées comme _font
est. Les finaliseurs sont utilisés pour nettoyer les ressources non gérées . Si vous n'exécutez pas la logique de nettoyage dans la méthode Dispose de votre (sous)classe, ils sont exécutés de manière non déterministe par le garbage collector.
Notez également que c'est très rarement que vous devez faire quoi que ce soit dans le destructeur. Régulièrement, tout est pris en charge par le garbage collector. Par exemple, dans votre code, vous n'avez pas besoin de disposer de l'objet _font
dans le destructeur de OwnerDrawnPanel
. Puisque le panneau est nettoyé par le GC, il en sera de même pour _font
, car le panneau était le seul qui l'a référencé, n'est-ce pas?
Généralement, si vous possédez des objets jetables, vous n'avez besoin de les disposer que lorsque votre Dispose
la méthode a été appelée. Mais PAS dans le destructeur. Lorsque votre destructeur est en cours d'exécution, vous pouvez parier que tous vos objets agrégés sont également nettoyés.
Vous ne devriez presque jamais avoir besoin d'utiliser des finaliseurs. Ils ne sont que pour les classes qui contiennent directement des ressources non gérées, et dans. net 2.0 + celles-ci doivent être enveloppées dans SafeHandle.
Je pense que Dispose(true)
libérera à la fois la ressource gérée et non gérée car nous ne devons plus appeler finalize c'est pourquoi nous écrivons GC.SupressFinalize()
après Dispose(true)
.
Nous appelons Dispose(false)
dans destructors pour libérer des ressources non gérées et seront appelés par Runtime et non par le code de l'utilisateur.
En accord avec Kumar, le modèle Dispose(bool disposing)
est également documenté sur MSDN . La distinction n'est pas entre les ressources gérées et non gérées, mais si Dispose
est appelé par votre code ou le runtime.
J'ai trouvé un bon article sur l'implémentation correcte de L'interface IDispose: http://msdn.microsoft.com/en-us/library/ms244737 (v=vs. 80).aspx
Le modèle de mise en œuvre d'un public public void Dispose()
, protected virtual void Dispose(bool)
, et ~ClassName()
finalizers est une bonne pratique recommandée par Microsoft comme un moyen d'organiser soigneusement votre code de nettoyage pour les ressources gérées et non gérées.
Fondamentalement, le code qui utilise votre Disposable
classe devrait appeler Dispose()
, mais si ce n'est pas le cas, le finaliseur {[2] } sera appelé par Garbage Collection, et en fonction de l'un de ceux-ci est utilisé, vous définissez l'argument sur Dispose(bool)
comme vrai ou faux, et dans votre Dispose(bool)
, Vous ne nettoyez les ressources gérées que si l'argument est vrai.
L'avertissement que vous obtenez semble spécifiquement vous recommandons d'utiliser cette pratique dans votre méthode finalize ~ClassName()
.