Question

J'ai quelques questions pour lesquelles je ne suis pas en mesure d'obtenir une réponse appropriée.

1) Pourquoi devrions-nous appeler SuppressFinalize dans la fonction Dispose une fois que nous n'avons pas destructor.

2) Evacuer et finaliser sont utilisés pour libérer des ressources avant que l'objet est nettoyé. Que ce soit géré ou d'une ressource non gérée, nous devons libérer, alors pourquoi nous avons besoin d'une condition dans la fonction Éliminez, en disant passage « vrai » quand nous appelons cette fonction surchargée de IDisposable. Jeter et passer de faux lorsqu'il est appelé à partir d'un Finaliser

Voir le code ci-dessous je copiais du net.

class Test : IDisposable
   {
     private bool isDisposed = false;

     ~Test()
     {
       Dispose(false);
     }

     protected void Dispose(bool disposing)
     {
       if (disposing)
       {
         // Code to dispose the managed resources of the class
       }
       // Code to dispose the un-managed resources of the class

       isDisposed = true;
     }

     public void Dispose()
     {
       Dispose(true);
       GC.SuppressFinalize(this);
     }
   }

si je supprimer la fonction booléenne protégée Dispose et mettons en œuvre le comme ci-dessous.

   class Test : IDisposable
   {
     private bool isDisposed = false;

     ~Test()
     {
       Dispose();
     }


     public void Dispose()
     {
      // Code to dispose the managed resources of the class
      // Code to dispose the un-managed resources of the class
      isDisposed = true;

      // Call this since we have a destructor . what if , if we don't have one 
       GC.SuppressFinalize(this);
     }
   }       
Était-ce utile?

La solution

Je vais sur une branche, mais ... la plupart des gens ne pas besoin le motif Éliminez complet. Il est conçu pour être solide face à un accès direct aux ressources non gérés (généralement via IntPtr) et face à l'héritage. La plupart du temps, aucun de ces est réellement nécessaire.

Si vous êtes juste une référence sur quelque chose d'autre qui met en œuvre IDisposable, vous certainement ne pas besoin d'un finaliseur - ce qui détient la ressource est directement responsable de traiter cela. Vous pouvez faire avec quelque chose comme ceci:

public sealed class Foo : IDisposable
{
    private bool disposed;
    private FileStream stream;

    // Other code

    public void Dispose()
    {
        if (disposed)
        {
            return;
        }
        stream.Dispose();
        disposed = true;
    }
}

Notez que cette est pas thread-safe, mais ce ne sera probablement pas un problème.

ne pas avoir à vous soucier de la possibilité de sous-classes, vous n'avez pas besoin détenant directement des ressources pour supprimer le finaliseur (parce qu'il n'y a pas) - et vous n'avez pas besoin de fournir un moyen de personnalisation de l'élimination des sous-classes Soit. La vie est plus simple sans héritage.

Si vous ne doivent permettre l'héritage non contrôlée (vous n'êtes pas prêt à parier que les sous-classes ont des besoins très particuliers) alors vous devez aller pour le modèle complet.

Notez que avec SafeHandle de .NET 2.0, il est encore plus rare que vous avez besoin de votre propre finaliseur qu'il était dans .NET 1.1.


Pour répondre à votre point de savoir pourquoi il y a un drapeau disposing en premier lieu: si vous utilisez dans un finaliseur, d'autres objets que vous référer à peut-être déjà été mis au point. Vous devez laisser les nettoyer eux-mêmes, et vous ne devez nettoyer les ressources dont vous directement propre.

Autres conseils

Gardez la première version, il est plus sûr et est la mise en œuvre correcte du motif Éliminez.

  1. L'appel SuppressFinalize indique au GC que vous avez fait toute la destruction / élimination vous (des ressources détenues par classe) et qu'il n'a pas besoin d'appeler le destructor.

  2. Vous devez le test au cas où le code en utilisant votre classe a déjà appelé et vous devez disposer ne pas dire le GC de disposer à nouveau.

Voir ce document de MSDN (Éliminez les méthodes doivent appeler SuppressFinalize).

Voici les principaux faits

1) Object.Finalize est ce que votre classe l'emporte quand il a un Finalizer. le ~ TypeName () méthode destructeur est juste un raccourci pour 'remplacer Finalize ()' etc

2) Vous appelez GC.SuppressFinalize si vous souhaitez vous débarrasser des ressources dans votre méthode Dispose avant la finalisation (à savoir en sortant d'un bloc à l'aide, etc.). Si vous ne disposez pas d'un Finalizer, alors vous n'avez pas besoin de le faire. Si vous avez un Finalizer, cela garantit que l'objet est retiré de la file d'attente Finalisation (donc nous DonT disposer de choses deux fois le Finalizer appelle généralement la méthode Dispose aussi bien)

3) Vous implémentez un Finalizer comme un mécanisme 'fail safe'. Finaliseurs sont garantis pour fonctionner (tant que le CLR nest pas avorté), ils vous permettent de faire le code que se nettoyer dans le cas où la méthode Dispose n'a pas été appelé (peut-être le programmeur a oublié de créer l'instance dans un « utilisant » bloc etc.

4) Finaliseurs sont chers comme les types qui ont finalizers BISEAUTONS déchets collectés dans une collection Génération-0 (le plus efficace), et sont promus à la génération 1 avec une référence à la file d'attente F-Joignable, de sorte que ils représentent une racine de GC. ce n'est pas jusqu'à ce que le GC réalise une collection Génération-1 que le finaliseur est appelé, et les ressources sont libérées - afin de mettre en œuvre finalizers que lorsque très important - et assurez-vous que les objets qui nécessitent Finalisation sont aussi petits que possible - car tous les objets qui peuvent être atteint par votre objet finalisables sera promu à la génération-1 également.

1. Réponse pour la première question

En fait, vous ne devez pas appeler la méthode SuppressFinalize si votre classe ne dispose pas d'une méthode finalize (Destructeur). Je crois que les gens appellent SupressFinalize même quand il n'y a pas de méthode finalize à cause du manque de connaissances.

2. Réponse à la deuxième question

Objet de la méthode Finaliser est de libérer des ressources non gérées. La chose la plus importante à comprendre est que, la méthode Finaliser est appelée lorsque l'objet est dans la file d'attente de finalisation. Garbage collector rassemble tous les objets qui peuvent être détruire. Garbage Collector ajoute des objets ceux-ci ont obtenu la finalisation de la file d'attente avant la finalisation détruire. Il y a un autre processus d'arrière-plan .net pour appeler la méthode finalize pour les objets ceux-ci sont dans la file d'attente de finalisation. Au moment où ce processus d'arrière-plan exécuter la méthode finalize, cette autre référence de gestion objet particulier peut avoir été détruite. Parce qu'il n'y a pas d'ordre spécifique en ce qui concerne l'exécution de finalisation. Ainsi, le modèle Dispose veut faire en sorte que la méthode finalize ne pas essayer d'accéder objets gérés. Voilà pourquoi les objets gérés vont dans le côté « si (la disposition) » clause qui est injoignable pour la méthode finale.

Vous devez toujours appeler SuppressFinalize () parce que vous pourriez avoir (ou dans l'avenir) une classe dérivée qui implémente un Finalizer - dans ce cas, vous en avez besoin.

Disons que vous avez une classe de base qui ne dispose pas d'un Finalizer - et vous avez décidé de ne pas appeler SuppressFinalize (). Puis 3 mois vous ajoutez plus tard une classe dérivée qui ajoute un Finalizer. Il est probable que vous allez oublier d'aller jusqu'à la classe de base et ajoutez un appel à SuppressFinalize (). Il n'y a pas de mal à l'appeler s'il n'y a pas finaliseur.

Mon suggéré modèle IDisposable est affiché ici: Comment mettre en œuvre correctement le modèle Dispose

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top