Czy powinienem wywołać Close () lub Dispose () dla obiektów stream?

Klasy takie jak Stream, StreamReader, StreamWriter etc implementuje interfejs IDisposable. Oznacza to, że możemy wywołać metodę Dispose() na obiektach tych klas. Zdefiniowali również metodę public o nazwie Close(). To mnie myli, jak mam się nazywać, gdy skończę z przedmiotami? A jeśli zadzwonię do obu?

Mój obecny kod to:

using (Stream responseStream = response.GetResponseStream())
{
   using (StreamReader reader = new StreamReader(responseStream))
   {
      using (StreamWriter writer = new StreamWriter(filename))
      {
         int chunkSize = 1024;
         while (!reader.EndOfStream)
         {
            char[] buffer = new char[chunkSize];
            int count = reader.Read(buffer, 0, chunkSize);
            if (count != 0)
            {
               writer.Write(buffer, 0, count);
            }
         }
         writer.Close();
      }
      reader.Close();
   }
}

Jak widzisz, napisałem using() konstrukty, które automatycznie wywołują metodę Dispose() na każdym obiekcie. Ale ja również nazywam Close() metodami. Czy to prawda?

Proszę zasugerować mi najlepsze praktyki podczas korzystania z obiektów stream. :-)

Przykład MSDN nie używa konstruktów using() i wywołuje metodę Close():

Czy to dobrze?
Author: Stas Ivanov, 2011-09-23

4 answers

Szybki skok do Reflector.NET pokazuje, że metoda Close() na StreamWriter wynosi:

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

I StreamReader jest:

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

The Dispose(bool disposing) override in StreamReader is:

protected override void Dispose(bool disposing)
{
    try
    {
        if ((this.Closable && disposing) && (this.stream != null))
        {
            this.stream.Close();
        }
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {
            this.stream = null;
            /* deleted for brevity */
            base.Dispose(disposing);
        }
    }
}

Metoda StreamWriter jest podobna.

Więc, czytając kod jest jasne, że można wywołać Close() & Dispose() na strumieniach tak często, jak chcesz i w dowolnej kolejności. To w żaden sposób nie zmieni zachowania.

Więc sprowadza się do tego, czy jest bardziej czytelny w użyciu Dispose(), Close() i / lub using ( ... ) { ... }.

Moje osobiste preferencje są takie, że using ( ... ) { ... } powinny być zawsze używane, gdy jest to możliwe, ponieważ pomaga "nie biegać z nożyczkami".

Ale, chociaż pomaga to poprawność, zmniejsza czytelność. W C# mamy już mnóstwo zamykających nawiasów klamrowych, więc skąd wiemy, który z nich faktycznie wykonuje Zamknięcie na strumieniu?

Więc myślę, że najlepiej jest to zrobić:

using (var stream = ...)
{
    /* code */

    stream.Close();
}

Nie wpływa to na zachowanie kodu, ale wspomaga czytelność.

 87
Author: Enigmativity,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-23 06:32:07

Nie, Nie należy wywoływać tych metod ręcznie. Na końcu bloku using automatycznie wywoływana jest metoda Dispose, która zadba o uwolnienie niezarządzanych zasobów (przynajmniej dla standardowych klas. NET BCL, takich jak streams, readers/writers, ...). Więc możesz też napisać swój kod w ten sposób:

using (Stream responseStream = response.GetResponseStream())
    using (StreamReader reader = new StreamReader(responseStream))
        using (StreamWriter writer = new StreamWriter(filename))
        {
            int chunkSize = 1024;
            while (!reader.EndOfStream)
            {
                 char[] buffer = new char[chunkSize];
                 int count = reader.Read(buffer, 0, chunkSize);
                 if (count != 0)
                 {
                     writer.Write(buffer, 0, count);
                 }
            }
         }

Metoda Close wywołuje Dispose.

 45
Author: Darin Dimitrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-23 09:55:25

Dokumentacja mówi, że te dwie metody są równoważne:

StreamReader.Close: implementacja Close wywołuje metodę Dispose przekazującą wartość true.

StreamWriter.Zamknij : Ta implementacja Close calls metody Dispose przekazując prawdziwą wartość.

Strumień.Close: ta metoda wywołuje Dispose, określając true, aby zwolnić wszystkie zasoby.

Więc oba są jednakowo "valid": {]}

/* Option 1 */
using (StreamWriter writer = new StreamWriter(filename)) { 
   // do something
} 

/* Option 2 */
StreamWriter writer = new StreamWriter(filename)
try {
    // do something
}
finally {
    writer.Close();
}

Osobiście trzymałbym się pierwszej opcji, ponieważ zawiera mniej "szumu".

 10
Author: Heinzi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-23 06:32:10

Na wielu klasach obsługujących zarówno metody Close, jak i Dispose, oba wywołania byłyby równoważne. Jednak na niektórych klasach możliwe jest ponowne otwarcie obiektu, który został zamknięty. niektóre takie klasy mogą utrzymać niektóre zasoby przy życiu po zamknięciu, w celu umożliwienia ponownego otwarcia; inne nie mogą utrzymać żadnych zasobów przy zamknięciu, ale mogą ustawić flagę na Dispose, aby wyraźnie zabronić ponownego otwarcia.

Umowa o IDisposable.Dispose jawnie wymaga, aby wywołanie go na obiekcie które nigdy nie zostaną użyte ponownie będą w najgorszym przypadku nieszkodliwe, więc polecam zadzwonić albo IDisposable.Dispose lub Metoda o nazwie Dispose na każdym IDisposable obiektu, niezależnie od tego, czy ktoś również wywołuje Close.

 3
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-23 19:22:15