web-dev-qa-db-fra.com

Est-ce que Stream.Dispose appelle toujours Stream.Close (et Stream.Flush)

Si j'ai la situation suivante:

StreamWriter MySW = null;
try
{
   Stream MyStream = new FileStream("asdf.txt");
   MySW = new StreamWriter(MyStream);
   MySW.Write("blah");
}
finally
{
   if (MySW != null)
   {
      MySW.Flush();
      MySW.Close();
      MySW.Dispose();
   }
}

Puis-je simplement appeler MySW.Dispose() et ignorer la fermeture même si elle est fournie? Existe-t-il des implémentations Stream qui ne fonctionnent pas comme prévu (comme CryptoStream)?

Sinon, le code suivant est tout simplement mauvais:

using (StreamWriter MySW = new StreamWriter(MyStream))
{
   MySW.Write("Blah");
}
62
JasonRShaver

Puis-je simplement appeler MySW.Dispose () et ignorer la fermeture même si elle est fournie?

Oui, c'est pour ça.

Existe-t-il des implémentations Stream qui ne fonctionnent pas comme prévu (comme CryptoStream)?

Il est sûr de supposer que si un objet implémente IDisposable, il se débarrassera de lui-même correctement.

Si ce n'est pas le cas, ce serait un bug.

Sinon, le code suivant est tout simplement mauvais:

Non, ce code est la méthode recommandée pour traiter les objets qui implémentent IDisposable.

Des informations plus excellentes se trouvent dans la réponse acceptée à Fermer et jeter - qui appeler?

81
Binary Worrier

J'ai utilisé Reflector et j'ai constaté que System.IO.Stream.Dispose ressemble à ça:

public void Dispose()
{
    this.Close();
}
58
Andrew Hare

Comme Daniel Bruckner l'a mentionné, Dispose et Close sont effectivement la même chose.

Cependant, Stream n'appelle PAS Flush () lorsqu'il est supprimé/fermé. FileStream (et je suppose que tout autre Stream avec un mécanisme de mise en cache) appelle Flush () lorsqu'il est supprimé.

Si vous étendez Stream, ou MemoryStream, etc., vous devrez implémenter un appel à Flush () lorsqu'il sera supprimé/fermé si nécessaire.

21
ScottS

StreamWriter.Dispose () et Stream.Dispose () libèrent toutes les ressources détenues par les objets. Tous deux ferment le flux sous-jacent.

Le code source de Stream.Dispose () (notez qu'il s'agit de détails d'implémentation donc ne vous y fiez pas):

public void Dispose()
{
    this.Close();
}

StreamWriter.Dispose () (identique à Stream.Dispose ()):

protected override void Dispose(bool disposing)
{
    try
    {
        // Not relevant things
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {
            try
            {
                if (disposing)
                {
                    this.stream.Close();
                }
            }
            finally
            {
                // Not relevant things
            }
        }
    }
}

Pourtant, je ferme généralement implicitement les flux/streamwriters avant de les éliminer - je pense que cela semble plus propre.

3
Tamas Czinege

Pour les objets qui doivent être fermés manuellement, tout doit être fait pour créer l'objet dans un bloc à l'aide.

//Cannot access 'stream'
using (FileStream stream = File.Open ("c:\\test.bin"))
{
   //Do work on 'stream'
} // 'stream' is closed and disposed of even if there is an exception escaping this block
// Cannot access 'stream' 

De cette façon, on ne peut jamais accéder de manière incorrecte à 'stream' hors du contexte de la clause using et le fichier est toujours fermé.

3
clemahieu

J'ai regardé dans la source .net pour la classe Stream, il y avait les éléments suivants qui suggèrent que oui, vous pouvez ...

    // Stream used to require that all cleanup logic went into Close(),
    // which was thought up before we invented IDisposable.  However, we 
    // need to follow the IDisposable pattern so that users can write
    // sensible subclasses without needing to inspect all their base
    // classes, and without worrying about version brittleness, from a
    // base class switching to the Dispose pattern.  We're moving 
    // Stream to the Dispose(bool) pattern - that's where all subclasses
    // should put their cleanup starting in V2. 
    public virtual void Close() 
    {
        Dispose(true); 
        GC.SuppressFinalize(this);
    }

    public void Dispose() 
    {
        Close(); 
    } 
3
Steve Sheldon

Tous les flux standard (FileStream, CryptoStream) tenteront de vider lorsqu'ils seront fermés/supprimés. Je pense que vous pouvez compter sur cela pour toutes les implémentations de flux Microsoft.

Par conséquent, Close/Dispose peut lever une exception si le vidage échoue.

En fait IIRC il y avait un bogue dans l'implémentation .NET 1.0 de FileStream en ce qu'il ne pourrait pas libérer le descripteur de fichier si le vidage lève une exception. Ce problème a été résolu dans .NET 1.1 en ajoutant un bloc try/finally à la méthode Dispose (boolean).

3
Joe

Stream.Close est implémenté par un appel à Stream.Dispose ou vice versa - les méthodes sont donc équivalentes. Stream.Close existe simplement parce que la fermeture d'un flux semble plus naturelle que la suppression d'un flux.

En outre, vous devriez essayer d'éviter les appels explicites à ces méthodes et utiliser à la place l'instruction using afin d'obtenir gratuitement une gestion correcte des exceptions.

2
Daniel Brückner