C# Language
Interface IDisposable
Recherche…
Remarques
C'est aux clients de la classe implémentant
IDisposable
de s'assurer qu'ils appellent la méthodeDispose
lorsqu'ils ont fini d'utiliser l'objet. Il n'y a rien dans le CLR qui recherche directement les objets pour qu'une méthodeDispose
appelle.Il n'est pas nécessaire d'implémenter un finaliseur si votre objet ne contient que des ressources gérées. Assurez-vous d'appeler
Dispose
sur tous les objets que votre classe utilise lorsque vous implémentez votre propre méthodeDispose
.Il est recommandé de sécuriser la classe contre les appels multiples à
Dispose
, même si elle ne devrait idéalement être appelée qu'une seule fois. Cela peut être réalisé en ajoutant une variableprivate bool
à votre classe et en définissant la valeur surtrue
lorsque la méthodeDispose
est exécutée.
Dans une classe contenant uniquement des ressources gérées
Les ressources gérées sont des ressources connues et contrôlées par le ramasse-miettes de l'environnement d'exécution. Il existe de nombreuses classes disponibles dans la BCL, par exemple, une classe SqlConnection
qui est une classe wrapper pour une ressource non gérée. Ces classes implémentent déjà l'interface IDisposable
- c'est à votre code de les nettoyer lorsque vous avez terminé.
Il n'est pas nécessaire d'implémenter un finaliseur si votre classe ne contient que des ressources gérées.
public class ObjectWithManagedResourcesOnly : IDisposable
{
private SqlConnection sqlConnection = new SqlConnection();
public void Dispose()
{
sqlConnection.Dispose();
}
}
Dans une classe avec des ressources gérées et non gérées
Il est important de laisser la finalisation ignorer les ressources gérées. Le finaliseur s'exécute sur un autre thread - il est possible que les objets gérés n'existent plus au moment où le finaliseur s'exécute. L'implémentation d'une méthode protégée Dispose(bool)
est une pratique courante pour s'assurer que les ressources gérées n'ont pas leur méthode Dispose
appelée depuis un finaliseur.
public class ManagedAndUnmanagedObject : IDisposable
{
private SqlConnection sqlConnection = new SqlConnection();
private UnmanagedHandle unmanagedHandle = Win32.SomeUnmanagedResource();
private bool disposed;
public void Dispose()
{
Dispose(true); // client called dispose
GC.SuppressFinalize(this); // tell the GC to not execute the Finalizer
}
protected virtual void Dispose(bool disposeManaged)
{
if (!disposed)
{
if (disposeManaged)
{
if (sqlConnection != null)
{
sqlConnection.Dispose();
}
}
unmanagedHandle.Release();
disposed = true;
}
}
~ManagedAndUnmanagedObject()
{
Dispose(false);
}
}
IDisposable, Dispose
.NET Framework définit une interface pour les types nécessitant une méthode de suppression:
public interface IDisposable
{
void Dispose();
}
Dispose()
est principalement utilisé pour nettoyer les ressources, comme les références non gérées. Cependant, il peut également être utile de forcer l’élimination des autres ressources même si elles sont gérées. Au lieu d'attendre que le GC finisse par nettoyer votre connexion à la base de données, vous pouvez vous assurer que cela est fait dans votre propre implémentation Dispose()
.
public void Dispose()
{
if (null != this.CurrentDatabaseConnection)
{
this.CurrentDatabaseConnection.Dispose();
this.CurrentDatabaseConnection = null;
}
}
Lorsque vous devez accéder directement à des ressources non managées, telles que des pointeurs non gérés ou des ressources win32, créez une classe héritant de SafeHandle
et utilisez les conventions / outils de cette classe pour le faire.
Dans une classe héritée avec des ressources gérées
Il est assez courant de créer une classe qui implémente IDisposable
, puis de dériver des classes contenant également des ressources gérées. Il est recommandé de marquer la méthode Dispose
avec le mot clé virtual
afin que les clients puissent nettoyer toutes les ressources dont ils sont propriétaires.
public class Parent : IDisposable
{
private ManagedResource parentManagedResource = new ManagedResource();
public virtual void Dispose()
{
if (parentManagedResource != null)
{
parentManagedResource.Dispose();
}
}
}
public class Child : Parent
{
private ManagedResource childManagedResource = new ManagedResource();
public override void Dispose()
{
if (childManagedResource != null)
{
childManagedResource.Dispose();
}
//clean up the parent's resources
base.Dispose();
}
}
en utilisant le mot clé
Lorsqu'un objet implémente l' IDisposable
interface, il peut être créé dans l' using
de la syntaxe:
using (var foo = new Foo())
{
// do foo stuff
} // when it reaches here foo.Dispose() will get called
public class Foo : IDisposable
{
public void Dispose()
{
Console.WriteLine("dispose called");
}
}
using
sucre syntatique pour un bloc try/finally
; l'utilisation ci-dessus se traduirait à peu près par:
{
var foo = new Foo();
try
{
// do foo stuff
}
finally
{
if (foo != null)
((IDisposable)foo).Dispose();
}
}