2009-03-07 2 views

Répondre

9

Il y a toujours un finaliseur dans IL - System.Object.Finalize() existe dans toutes les classes, donc si vous faites une classe personnalisée, il a un finaliseur que vous voulez supprimer. Cela étant dit, tous les objets ne sont pas placés dans la file d'attente de finalisation, donc vous ne devriez avoir besoin de supprimer la finalisation que si vous implémentez votre propre finaliseur. Si vous implémentez IDisposable pour encapsuler des ressources non managées, vous devez inclure un finaliseur, et vous devez l'empêcher d'être exécuté, car en théorie vous effectuez le nettoyage déjà lorsque Dispose est appelé.

+0

True. En outre, vous devez avoir un finaliseur qui appelle Dispose(). – configurator

+0

True-Object.Finalize est une opération nulle, mais si vous implémentez IDisposable, vous dites que vous avez des ressources à libérer. De MSDN, cela signifie que vous devriez toujours avoir un finaliseur pour les libérer, afin qu'ils soient manipulés correctement. Cela signifie que Finalize appelle Dispose et Dispose supprime la finalisation. –

+4

@configurator Vous ne devriez avoir un finaliseur que si vous possédez directement des ressources non managées (comme des handles). Si vous ne les possédez qu'indirectement, par ex. une référence à un FileStream, pourquoi devriez-vous écrire quelque chose de plus que IDisposable.Dispose() {if (fs! = null) {fs.Dispose(); fs = null; }}? IMO, StyleCop est un outil horrible qui force beaucoup de texte inutile à être écrit et maintenu, et n'ajoute aucune valeur commerciale en retour. –

2

Tous les objets ont une méthode de finalisation, même si vous n'en avez pas implémenté en utilisant un destructeur C# (qui n'est pas garanti d'être appelé par le GC). C'est une bonne pratique de supprimer l'appel si vous avez implémenté IDisposable car cela signifie que vous avez décidé d'effectuer la finalisation de manière explicite.

devx article

+0

Pourriez-vous expliquer le «pas garanti d'être appelé par le GC»? –

+0

Lors de la fermeture du programme, certains objets risquent de ne pas pouvoir exécuter leurs finaliseurs si le nettoyage prend trop de temps. Cela pourrait être ce à quoi il fait allusion. –

+0

Oui, c'est ce dont je parlais. – x0n

2

Je ne vois aucun besoin d'appeler SuppressFinalize() s'il n'y a pas de finaliseur défini. Si vous voulez être sur la défensive, il peut être bon d'avoir un finaliseur ainsi que Dispose(), donc vous n'avez pas besoin de compter sur les clients pour toujours appeler Dispose(). Alors vous ne ferez pas de fuites de ressources quand ils oublient.

+0

Si un objet est "responsable" d'autres objets, IDisposable, mais n'a pas de ressources non gérées, il doit alors être Dispose mais pas Finalizer. –

20

Il n'y a pas besoin d'appeler GC.SuppressFinalize(this) en Dispose, à moins que:

  • Vous êtes la classe de base qui met en œuvre des méthodes Dispose virtuelles destinées pour des raisons impérieuses (encore une fois, il pourrait ne pas être de votre responsabilité, même ici, mais vous voudrez peut-être pour le faire dans ce cas)
  • Vous avez un finaliseur vous-même. Techniquement, toutes les classes .NET a un finaliseur, mais si présent que finaliseur est celui Object, l'objet n'est pas considéré nécessaire Finaliser et n'est pas mis sur la liste de finalisation sur GC

I dirait, en supposant que vous n'avez aucun des cas ci-dessus, que vous pouvez ignorer ce message en toute sécurité.

+1

Quand une classe dérivée * EVER * devrait-elle ajouter un finaliseur à une classe de base non triviale? Pourquoi ajouter du code pour permettre à une classe dérivée de faire quelque chose qu'elle ne devrait jamais faire? – supercat

+0

@supercat Si une classe dérivée possède des ressources non managées, elle doit avoir un finaliseur pour s'assurer qu'elles sont libérées. Si l'objet est toujours utilisé correctement (avec une instruction try-finally ou, de manière équivalente, using), Dispose effectuera le nettoyage et supprimera le finaliseur, mais le finalizer s'assurera que les ressources non managées sont finalement libérées (lorsque l'objet est collecté) même si Dispose n'a jamais été appelé (par exemple en raison d'une exception et de l'impossibilité de protéger un bloc de code). –

+1

@TheDag: Chaque ressource non managée qui nécessite un nettoyage du finalizer doit presque toujours être encapsulée dans son propre objet qui doit soit dériver de 'Object', soit un type de base abstrait explicitement conçu pour faciliter ce nettoyage. Le type résultant serait alors une ressource gérée, à laquelle une référence pourrait être retenue par le plus grand type. Le nettoyage de finalisation serait pris en charge par le plus petit objet d'encapsulation; l'objet plus gros n'aurait pas besoin d'un finaliseur. – supercat

Questions connexes