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()
:
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ść.
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.
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".
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.
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