Finaliser / éliminer le modèle en C#

C# 2008

j'y travaille depuis un moment maintenant, et je suis encore confus sur certaines questions. Mes questions sont ci-dessous

  1. je sais que vous n'avez besoin d'un finaliseur que si vous disposez de ressources non gérées. Cependant, si vous utilisez des ressources gérées qui font des appels à des ressources non gérées, auriez-vous encore besoin de mettre en œuvre un finalizer?

  2. toutefois, si vous développez une classe qui n'utilise aucune ressource non gérée, directement ou indirectement, pouvez-vous mettre en œuvre le IDisposable afin que les clients de votre classe puissent utiliser le "user statement"?

    serait-il acceptable d'implémenter L'IDisposable juste pour que les clients de votre classe puissent utiliser la déclaration d'utilisation?

    using(myClass objClass = new myClass())
    {
        // Do stuff here
    }
    
  3. j'ai développé ce code simple ci-dessous pour démontrer le modèle de finalisation/élimination:

    public class NoGateway : IDisposable
    {
        private WebClient wc = null;
    
        public NoGateway()
        {
            wc = new WebClient();
            wc.DownloadStringCompleted += wc_DownloadStringCompleted;
        }
    
    
        // Start the Async call to find if NoGateway is true or false
        public void NoGatewayStatus()
        {
            // Start the Async's download
                // Do other work here
            wc.DownloadStringAsync(new Uri(www.xxxx.xxx));
        }
    
        private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            // Do work here
        }
    
        // Dispose of the NoGateway object
        public void Dispose()
        {
            wc.DownloadStringCompleted -= wc_DownloadStringCompleted;
            wc.Dispose();
            GC.SuppressFinalize(this);
        }
    }
    

Question sur le code source:

  1. ici je n'ai pas ajouté le finalizer, et normalement le finalizer sera appelé par le GC, et le finalizer appellera Le Dispose. Comme je n'ai pas le finalizer, Quand dois-je appeler la méthode Dispose? Est-ce le client de la classe qui doit l'appeler?

    ainsi ma classe dans l'exemple s'appelle NoGateway et le client pourrait utiliser et disposer de la classe comme ceci:

    using(NoGateway objNoGateway = new NoGateway())
    {
        // Do stuff here   
    }
    

    la méthode Dispose sera - t-elle automatiquement appelée lorsque l'exécution atteint la fin du bloc d'utilisation, ou le client doit-il appeler manuellement la méthode dispose? c'est à dire

    NoGateway objNoGateway = new NoGateway();
    // Do stuff with object
    objNoGateway.Dispose(); // finished with it
    
  2. j'utilise la classe webclient dans ma classe NoGateway . Parce que le webclient implémente L'interface IDisposable, est-ce que cela signifie que le webclient utilise indirectement non géré ressources? Est-il une règle dure et rapide à suivre à ce sujet? Comment puis-je savoir qu'une classe utilise des ressources non managées?

338
demandé sur samis 2009-05-22 20:44:45

13 réponses

le motif IDisposable recommandé est ici . Lors de la programmation d'une classe qui utilise IDisposable, généralement vous devez utiliser deux modèles:

lors de la mise en œuvre D'une classe scellée qui n'utilise pas de ressources non gérées, vous mettez simplement en œuvre une méthode D'élimination comme avec des implémentations d'interface normales:

public sealed class A : IDisposable
{
    public void Dispose()
    {
        // get rid of managed resources, call Dispose on member variables...
    }
}

lors de la mise en œuvre d'une classe non scellée, faites-le comme ceci:

public class B : IDisposable
{    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    }

    // only if you use unmanaged resources directly in B
    //~B()
    //{
    //    Dispose(false);
    //}
}

Notez que je n'ai pas déclaré de finalizer dans B ; vous ne devez mettre en œuvre un finalizer que si vous avez des ressources réelles non gérées à disposer. Le CLR traite les objets finalisables différemment des objets non finalisables, même si SuppressFinalize est appelé.

donc, vous ne devriez pas déclarer un finalizer sauf si vous devez, mais vous donnez aux héritiers de votre classe un crochet pour appeler votre Dispose et mettre en œuvre un finalizer eux-mêmes s'ils utilisent des ressources non gérées directement:

public class C : B
{
    private IntPtr m_Handle;

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }
        ReleaseHandle(m_Handle);

        base.Dispose(disposing);
    }

    ~C() {
        Dispose(false);
    }
}

si vous n'utilisez pas directement des ressources non gérées ( SafeHandle et les amis ne comptent pas, car ils déclarent leurs propres finaliseurs), alors ne mettez pas en œuvre un finaliseur, car le GC traite les classes finalisables différemment, même si vous supprimez plus tard le finaliseur. Notez également que, même si B n'a pas de finalizer, il appelle toujours SuppressFinalize pour traiter correctement avec toute sous-classe qui ne mettent en œuvre un finalizer.

Lorsqu'une classe implémente L'interface IDisposable, cela signifie qu'il y a quelque part des ressources non gérées qui devraient être éliminées lorsque vous avez terminé d'utiliser la classe. Les ressources réelles sont encapsulées dans les classes; vous n'avez pas besoin de les supprimer explicitement. Le simple fait d'appeler Dispose() ou d'envelopper la classe dans un using(...) {} permettra de s'assurer que toutes les ressources non gérées sont débarrassées au besoin.

382
répondu thecoop 2016-11-29 12:52:40

le schéma officiel pour mettre en œuvre IDisposable est difficile à comprendre. Je crois que celui-ci est meilleur :

public class BetterDisposableClass : IDisposable {

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

  protected virtual void CleanUpManagedResources() { 
    // ...
  }
  protected virtual void CleanUpNativeResources() {
    // ...
  }

  ~BetterDisposableClass() {
    CleanUpNativeResources();
  }

}

Un encore mieux la solution est d'avoir une règle qui vous toujours créer une classe wrapper pour toute ressource non managée que vous avez besoin pour gérer:

public class NativeDisposable : IDisposable {

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

  protected virtual void CleanUpNativeResource() {
    // ...
  }

  ~NativeDisposable() {
    CleanUpNativeResource();
  }

}

avec SafeHandle et ses dérivés, ces les classes devraient être très rare .

le résultat pour les classes jetables qui ne traitent pas directement avec des ressources non gérées, même en présence d'héritage, est puissant: ils n'ont plus besoin d'être concernés avec des ressources non gérées plus . Ils seront simple à mettre en œuvre et à comprendre:

public class ManagedDisposable : IDisposable {

  public virtual void Dispose() {
    // dispose of managed resources
  }

}
110
répondu Jordão 2011-03-29 15:52:26

notez que toute mise en œuvre IDisposable doit suivre le modèle ci-dessous (IMHO). J'ai développé ce modèle basé sur l'information de plusieurs excellents .net "gods" le .net Framework Design Guidelines (notez que MSDN ne suit pas cela pour une raison quelconque!). Les directives de conception du. Net ont été rédigées par Krzysztof Cwalina (architecte CLR à l'époque) et Brad Abrams (je crois que le directeur de programme CLR à l'époque) et Bill Wagner ([en vigueur C#] et [Suite Efficace c#] (il suffit de jeter un oeil à ces sur Amazon.com:

notez que vous ne devez jamais implémenter un Finalizer à moins que votre classe ne contienne directement (et non pas hérite) des ressources non gérées. Une fois que vous mettez en œuvre un Finalizer dans une classe, même si elle n'est jamais appelée, il est garanti de vivre pour une collection supplémentaire. Il est automatiquement placé sur la file D'attente de finalisation (qui s'exécute sur un seul thread). Aussi, on remarque très importante...tout le code exécuté dans un Finalizer (si vous besoin de mettre en œuvre un) doit être thread-safe et exception-safe! De mauvaises choses se produiront autrement...(c'est-à-dire un comportement indéterminé et dans le cas d'une exception, un accident fatal d'application irrécupérable).

le modèle que j'ai mis en place (et écrit un extrait de code pour) suit:

#region IDisposable implementation

//TODO remember to make this class inherit from IDisposable -> $className$ : IDisposable

// Default initialization for a bool is 'false'
private bool IsDisposed { get; set; }

/// <summary>
/// Implementation of Dispose according to .NET Framework Design Guidelines.
/// </summary>
/// <remarks>Do not make this method virtual.
/// A derived class should not be able to override this method.
/// </remarks>
public void Dispose()
{
    Dispose( true );

    // This object will be cleaned up by the Dispose method.
    // Therefore, you should call GC.SupressFinalize to
    // take this object off the finalization queue 
    // and prevent finalization code for this object
    // from executing a second time.

    // Always use SuppressFinalize() in case a subclass
    // of this type implements a finalizer.
    GC.SuppressFinalize( this );
}

/// <summary>
/// Overloaded Implementation of Dispose.
/// </summary>
/// <param name="isDisposing"></param>
/// <remarks>
/// <para><list type="bulleted">Dispose(bool isDisposing) executes in two distinct scenarios.
/// <item>If <paramref name="isDisposing"/> equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.</item>
/// <item>If <paramref name="isDisposing"/> equals false, the method has been called by the 
/// runtime from inside the finalizer and you should not reference 
/// other objects. Only unmanaged resources can be disposed.</item></list></para>
/// </remarks>
protected virtual void Dispose( bool isDisposing )
{
    // TODO If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource.
    try
    {
        if( !this.IsDisposed )
        {
            if( isDisposing )
            {
                // TODO Release all managed resources here

                $end$
            }

            // TODO Release all unmanaged resources here



            // TODO explicitly set root references to null to expressly tell the GarbageCollector
            // that the resources have been disposed of and its ok to release the memory allocated for them.


        }
    }
    finally
    {
        // explicitly call the base class Dispose implementation
        base.Dispose( isDisposing );

        this.IsDisposed = true;
    }
}

//TODO Uncomment this code if this class will contain members which are UNmanaged
// 
///// <summary>Finalizer for $className$</summary>
///// <remarks>This finalizer will run only if the Dispose method does not get called.
///// It gives your base class the opportunity to finalize.
///// DO NOT provide finalizers in types derived from this class.
///// All code executed within a Finalizer MUST be thread-safe!</remarks>
//  ~$className$()
//  {
//     Dispose( false );
//  }
#endregion IDisposable implementation

voici le code pour implémenter IDisposable dans une classe dérivée. Notez que vous n'avez pas besoin d'énumérer explicitement l'héritage D'IDisposable dans définition de la classe dérivée.

public DerivedClass : BaseClass, IDisposable (remove the IDisposable because it is inherited from BaseClass)


protected override void Dispose( bool isDisposing )
{
    try
    {
        if ( !this.IsDisposed )
        {
            if ( isDisposing )
            {
                // Release all managed resources here

            }
        }
    }
    finally
    {
        // explicitly call the base class Dispose implementation
        base.Dispose( isDisposing );
    }
}

j'ai posté cette implémentation sur mon blog à: comment mettre en œuvre correctement le modèle Dispose

33
répondu Dave Black 2016-04-22 13:25:29

je suis d'accord avec pm100 (et j'aurais dû le dire explicitement dans mon billet précédent).

vous ne devez jamais implémenter IDisposable dans une classe sauf si vous en avez besoin. Pour être très précis, il y a environ 5 fois où vous auriez besoin/devriez implémenter IDisposable:

  1. votre classe contient explicitement (c'est-à-dire pas par héritage) toutes les ressources gérées qui implémentent IDisposable et doivent être nettoyées une fois que votre classe n'est pas plus utilisé. Par exemple, si votre classe contient une instance D'un Stream, DbCommand, datable, etc.

  2. votre classe contient explicitement toutes les ressources gérées qui implémentent une méthode Close () - par exemple IDataReader, IDbConnection, etc. Notez que certaines de ces classes implémentent IDisposable en ayant Dispose() ainsi qu'une méthode Close ().

  3. votre classe contient explicitement une ressource non gérée-e.g. un objet COM, des pointeurs (oui, vous pouvez utiliser des pointeurs dans managed C# mais ils doivent être déclarés dans les blocs 'unsafe', etc. Dans le cas de ressources non gérées, vous devez également vous assurer d'appeler le système.Runtime.InteropServices.Maréchal.ReleaseComObject() sur le BRF. Même si la RCW est, en théorie, un papier d'emballage géré, il y a toujours des comptes de référence en cours sous les couvertures.

  4. si votre classe souscrit à des événements en utilisant des références fortes. Vous avez besoin de se désinscrire / se détacher des événements. Toujours pour s'assurer que ceux-ci ne sont pas nuls avant d'essayer de les désinscrire/Les détacher!.

  5. votre classe comprend une combinaison des catégories ci-dessus...

Une alternative à l'utilisation d'objets COM et d'avoir à utiliser le Maréchal.ReleaseComObject () doit utiliser le système.Runtime.InteropServices.Classe SafeHandle.

la BCL (classe de Base Team Library) a un bon billet de blog à ce sujet ici http://blogs.msdn.com/bclteam/archive/2005/03/16/396900.aspx

une remarque très importante à faire est que si vous travaillez avec la WCF et le nettoyage des ressources, vous devriez presque toujours éviter le bloc "utiliser". Il ya beaucoup de billets de blog là-bas et certains sur MSDN sur les raisons pour lesquelles c'est une mauvaise idée. J'ai aussi posté à ce sujet ici - N'utilisez pas 'using ()' avec un mandataire WCF

19
répondu Dave Black 2016-04-21 16:13:51

utilisant lambdas au lieu de IDisposable.

Je n'ai jamais été enthousiasmé par l'idée d'utiliser/IDisposable. Le problème est que l'appelant doit:

  • savoir qu'ils doivent utiliser IDisposable
  • n'oubliez pas d'utiliser 'l'aide'.

Ma nouvelle méthode préférée consiste à utiliser une méthode de fabrique et un lambda au lieu de

Imaginez que je veux faire quelque chose avec un SqlConnection (quelque chose qui devrait être enveloppé dans une utilisation). Classiquement, vous feriez

using (Var conn = Factory.MakeConnection())
{
     conn.Query(....);
}

Nouvelle manière

Factory.DoWithConnection((conn)=>
{
    conn.Query(...);
}

dans le premier cas, l'appelant ne pouvait tout simplement pas utiliser la syntaxe d'utilisation. DANS le second cas, l'utilisateur n'a pas le choix. Il n'y a pas de méthode qui crée un objet SqlConnection, l'appelant doit invoquer DoWithConnection.

Dowthithconnection looks like this

void DoWithConnection(Action<SqlConnection> action)
{
   using (var conn = MakeConnection())
   {
       action(conn);
   }
}

MakeConnection est maintenant privé

11
répondu pm100 2016-04-01 20:11:17

personne n'a répondu à la question de savoir si vous devez implémenter IDisposable même si vous n'en avez pas besoin.

brève réponse: non

longue réponse:

cela permettrait à un consommateur de votre catégorie d'utiliser "Utiliser". La question que je poserais est: pourquoi le feraient - ils? La plupart des devs n'utiliseront pas 'utiliser' à moins qu'ils ne sachent qu'ils doivent - et comment le savent-ils. Soit

  • son obviuos eux de l'expérience (une classe de socket par exemple)
  • documentés
  • ils sont prudents et peuvent voir que la classe implémente IDisposable

donc en implémentant IDisposable vous dites aux devs (au moins certains) que cette classe boucle quelque chose qui doit être libéré. Ils utiliseront "utiliser" - mais il y a d'autres cas où l'utilisation n'est pas possible (la portée de l'objet n'est pas locale); et ils devront commencer s'inquiéter de la durée de vie des objets dans ces autres cas - je m'inquiéterais à coup sûr. Mais ce n'est pas nécessaire

vous implémentez Idisposable pour leur permettre d'utiliser using, mais ils n'utiliseront pas using à moins que vous ne leur demandiez de le faire.

Afin de ne pas le faire

9
répondu pm100 2010-01-13 21:53:49
  1. si vous utilisez d'autres objets gérés qui utilisent des ressources non gérées, il n'est pas de votre responsabilité de vous assurer qu'ils sont finalisés. Votre responsabilité est d'appeler disposer sur ces objets quand Dispose est appelé sur votre objet, et il s'arrête là.

  2. si votre classe n'utilise pas de ressources rares, Je ne vois pas pourquoi vous rendriez votre classe implémenter IDisposable. Vous devriez le faire que si vous êtes:

    • Savez vous avez des ressources limitées de vos objets rapidement, tout simplement pas maintenant (et je veux dire que, comme dans "nous sommes encore en développement, il sera ici avant que nous ayons terminé", pas comme dans "je pense que nous en aurons besoin")
    • Utilisation de ressources rares
  3. Oui, le code qui utilise votre code doit appeler la méthode dispose de l'objet. Et oui, le code qui utilise votre objet peut utiliser using comme vous avez illustré.

  4. (2 encore?) Il est probable que le WebClient utilise soit des ressources non gérées, soit d'autres ressources gérées qui mettent en œuvre IDisposable. La raison exacte, cependant, n'est pas importante. Ce qui est important, c'est qu'il implémente IDisposable, et c'est donc à vous d'agir sur cette connaissance en vous débarrassant de l'objet lorsque vous en avez fini avec lui, même s'il s'avère que WebClient n'utilise pas d'autres ressources du tout.

4
répondu Lasse Vågsæther Karlsen 2009-05-22 16:55:34

@Icey,

en fait votre réponse est légèrement incorrecte pour 2 raisons:

Première", 151940920"

using(NoGateway objNoGateway = new NoGateway())

correspond en fait à:

try
{
    NoGateway = new NoGateway();
}
finally
{
    if(NoGateway != null)
    {
        NoGateway.Dispose();
    }
}

cela peut sembler ridicule puisque le "nouvel" opérateur ne devrait jamais retourner "null" à moins que vous ayez une exception OutOfMemory. Mais considérons les cas suivants: 1. Vous appelez FactoryClass qui renvoie une ressource IDisposable ou 2. Si vous avez un type de qui peut hériter ou ne pas hériter D'IDisposable selon son implémentation-rappelez-vous que J'ai vu le modèle IDisposable implémenté incorrectement de nombreuses fois chez de nombreux clients où les développeurs viennent d'ajouter une méthode Dispose() sans hériter D'IDisposable (bad, bad, bad). Vous pourriez aussi avoir le cas d'une ressource IDisposable retournée à partir d'un bien ou d'une méthode (encore une fois mauvais, mauvais, mauvais - ne donnez pas vos ressources Idisposables)

using(IDisposable objNoGateway = new NoGateway() as IDisposable)
{
    if (NoGateway != null)
    {
        ...

Si le "comme" l'opérateur renvoie null (ou la propriété ou la méthode renvoie la ressource), et votre code dans le bloc 'using' protège contre 'null', votre code ne explosera pas en essayant d'appeler Dispose sur un objet null à cause du contrôle null 'intégré'.

la deuxième raison pour laquelle votre réponse n'est pas exacte est à cause du stmt suivant:

un finaliseur est appelé sur le GC détruire votre objet

First, La finalisation (ainsi que la GC elle-même) est non déterministe. Le CLR détermine quand il appellera un finaliseur. c'est à dire le développeur/code n'a aucune idée. Si le modèle IDisposable est mis en œuvre correctement (comme je l'ai indiqué ci-dessus) et GC.SuppressFinalize() a été appelé, le Finalizer ne sera pas appelé. C'est l'une des principales raisons pour mettre correctement en œuvre le modèle correctement. Comme il n'y a qu'un seul thread Finalizer par processus géré, quel que soit le nombre de processeurs logiques, vous pouvez dégradez facilement les performances en sauvegardant ou même en suspendant le thread Finalizer en oubliant d'appeler GC.SuppressFinalize ().

j'ai posté une mise en œuvre correcte du modèle Dispose sur mon blog: comment mettre en œuvre correctement le modèle Dispose

4
répondu Dave Black 2016-10-03 17:36:36

modèle dispose:

public abstract class DisposableObject : IDisposable
{
    public bool Disposed { get; private set;}      

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

    ~DisposableObject()
    {
        Dispose(false);
    }

    private void Dispose(bool disposing)
    {
        if (!Disposed)
        {
            if (disposing)
            {
                DisposeManagedResources();
            }

            DisposeUnmanagedResources();
            Disposed = true;
        }
    }

    protected virtual void DisposeManagedResources() { }
    protected virtual void DisposeUnmanagedResources() { }
}

exemple d'héritage:

public class A : DisposableObject
{
    public Component components_a { get; set; }
    private IntPtr handle_a;

    protected override void DisposeManagedResources()
    {
        try
        {
          Console.WriteLine("A_DisposeManagedResources");
          components_a.Dispose();
          components_a = null;
        }
        finally
        { 
          base.DisposeManagedResources();
        }
    }

    protected override void DisposeUnmanagedResources()
    {
        try
        {
          Console.WriteLine("A_DisposeUnmanagedResources");
          CloseHandle(handle_a);
          handle_a = IntPtr.Zero;
        }
        finally
        { 
          base.DisposeUnmanagedResources();
        }
    }
}

public class B : A
{
    public Component components_b { get; set; }
    private IntPtr handle_b;

    protected override void DisposeManagedResources()
    {
        try
        {
          Console.WriteLine("B_DisposeManagedResources");
          components_b.Dispose();
          components_b = null;
        }
        finally
        { 
          base.DisposeManagedResources();
        }
    }

    protected override void DisposeUnmanagedResources()
    {
        try
        {
          Console.WriteLine("B_DisposeUnmanagedResources");
          CloseHandle(handle_b);
          handle_b = IntPtr.Zero;
        }
        finally
        { 
          base.DisposeUnmanagedResources();
        }
    }
}
3
répondu Andrei Krasutski 2014-08-28 11:46:03
using(NoGateway objNoGateway = new NoGateway())

est l'équivalent de

try
{
    NoGateway = new NoGateway();
}

finally
{
    NoGateway.Dispose();
}

un finaliseur est appelé sur le GC détruire votre objet. Cela peut être à un moment totalement différent que lorsque vous quittez votre méthode. La disposition D'IDisposable est appelée immédiatement après que vous ayez quitté le bloc d'utilisation. Par conséquent, le modèle est généralement à utiliser en utilisant des ressources gratuites immédiatement après que vous n'en avez plus besoin.

2
répondu Daniel Fabian 2009-05-22 16:50:11

1) WebClient est un type géré, donc vous n'avez pas besoin d'un finalizer. Le finalizer est nécessaire dans le cas où vos utilisateurs ne disposent pas() de votre classe NoGateway et le type natif (qui n'est pas collecté par le GC) doit être nettoyé après. Dans ce cas, si L'utilisateur n'appelle pas Dispose (), le WebClient contenu sera éliminé par le GC immédiatement après le NoGateway.

2) Indirectement oui, mais vous ne devriez pas avoir à vous en préoccuper. Votre code est correct comme se tient debout et vous ne pouvez pas empêcher vos utilisateurs d'oublier de se débarrasser de() très facilement.

2
répondu Jesse C. Slicer 2009-05-22 16:50:58

Modèle à partir de msdn

public class BaseResource: IDisposable
{
   private IntPtr handle;
   private Component Components;
   private bool disposed = false;
   public BaseResource()
   {
   }
   public void Dispose()
   {
      Dispose(true);      
      GC.SuppressFinalize(this);
   }
   protected virtual void Dispose(bool disposing)
   {
      if(!this.disposed)
      {        
         if(disposing)
         {
            Components.Dispose();
         }         
         CloseHandle(handle);
         handle = IntPtr.Zero;
       }
      disposed = true;         
   }
   ~BaseResource()      
   {      Dispose(false);
   }
   public void DoSomething()
   {
      if(this.disposed)
      {
         throw new ObjectDisposedException();
      }
   }
}
public class MyResourceWrapper: BaseResource
{
   private ManagedResource addedManaged;
   private NativeResource addedNative;
   private bool disposed = false;
   public MyResourceWrapper()
   {
   }
   protected override void Dispose(bool disposing)
   {
      if(!this.disposed)
      {
         try
         {
            if(disposing)
            {             
               addedManaged.Dispose();         
            }
            CloseHandle(addedNative);
            this.disposed = true;
         }
         finally
         {
            base.Dispose(disposing);
         }
      }
   }
}
1
répondu devnull 2010-03-28 09:52:50

de ce que je sais, il est fortement recommandé de ne pas utiliser le finaliseur / destructeur:

public ~MyClass() {
  //dont use this
}

la plupart du temps, cela est dû à ne pas savoir quand ou si elle sera appelée. La méthode d'élimination est beaucoup mieux, surtout si vous nous utilisez ou éliminez directement.

utiliser est bon. l'utiliser :)

-4
répondu Nic Wise 2009-05-22 16:56:53