Klasy takich jak Stream
, StreamReader
, StreamWriter
itp osprzęt IDisposable
interfejsu. Oznacza to, że możemy wywołać Dispose()
metodę na obiektach tych klas. Zdefiniowali również public
metodę o nazwie Close()
. To mnie wprawia w zakłopotanie, co mam nazwać, 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()
konstrukcje, które automatycznie wywołują Dispose()
metodę na każdym obiekcie. Ale nazywam też Close()
metody. Czy to jest poprawne?
Proszę zasugerować najlepsze praktyki podczas używania obiektów strumieniowych. :-)
Przykład MSDN nie używa using()
konstrukcji i wywołania Close()
metody:
Czy to jest dobre?
using (MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream()) { }
. Mam na myśli to w ten sposób, w którym można przedefiniować typ:using (MemoryStream ms = new MemoryStream()) using (FileStream fs = File.OpenRead("c:\\file.txt")) { }
Odpowiedzi:
Szybki skok do Reflector.NET pokazuje, że
Close()
metoda naStreamWriter
to:I
StreamReader
jest:Dispose(bool disposing)
Przesłanianie wStreamReader
IS:StreamWriter
Sposób jest podobny.Tak więc, czytając kod, jest jasne, że możesz dzwonić
Close()
i korzystaćDispose()
ze strumieni tak często, jak chcesz iw dowolnej kolejności. Nie zmieni to w żaden sposób zachowania.Sprowadza się więc do tego, czy jest bardziej czytelny w użyciu
Dispose()
,Close()
i / lubusing ( ... ) { ... }
.Moje osobiste preferencje są takie, że
using ( ... ) { ... }
powinno się je stosować zawsze, gdy to możliwe, ponieważ pomaga to „nie biegać z nożyczkami”.Ale chociaż pomaga to w poprawności, 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 w strumieniu?
Więc myślę, że najlepiej zrobić to:
Nie wpływa na zachowanie kodu, ale poprawia czytelność.
źródło
Close()
wezwaniem. Jeśli ktoś mniej doświadczony spojrzy na kod i nie będzie o nim wiedziałusing
, to: 1) sprawdzi i nauczy się , lub 2) na ślepo dodaClose()
ręcznie. Jeśli wybierze 2), być może jakiś inny programista zobaczy zbędneClose()
i zamiast „chichotać” poinstruuje mniej doświadczonego programistę. Nie jestem zwolennikiem utrudniania życia niedoświadczonym programistom, ale jestem zwolennikiem przekształcania ich w doświadczonych programistów.Nie, nie powinieneś wywoływać tych metod ręcznie. Na końcu
using
blokuDispose()
automatycznie wywoływana jest metoda, która zadba o zwolnienie niezarządzanych zasobów (przynajmniej dla standardowych klas .NET BCL, takich jak strumienie, czytniki / pisarze, ...). Możesz więc również napisać swój kod w ten sposób:Close()
Wywołuje metodęDispose()
.źródło
using
pierwszy,responseStream
ponieważ jest opakowany przez,reader
który upewni się, że zostanie zamknięty, gdy czytnik zostanie usunięty. Jednak +1The Close method calls Dispose.
... aw pozostałej części twojego postu sugerujesz,Dispose()
że zadzwoniłbymClose()
, nie powinienem dzwonić do tego ostatniego ręcznie. Mówisz, że dzwonią do siebie?using
bloku. Implementuję klasę, która pisze od czasu do czasu i dlatego nie może.using
(lub, ponownie, przejdź do wzorca Dispose).Dokumentacja mówi, że te dwie metody są równoważne:
Tak więc oba są równie ważne:
Osobiście trzymałbym się pierwszej opcji, ponieważ zawiera ona mniej „szumu”.
źródło
W przypadku wielu klas, które obsługują obie
Close()
iDispose()
metody, te dwa wywołania byłyby równoważne. Jednak na niektórych zajęciach możliwe jest ponowne otwarcie obiektu, który został zamknięty. Niektóre takie klasy mogą utrzymywać przy życiu niektóre zasoby po Zamknięciu, aby umożliwić ich ponowne otwarcie; inni mogą nie utrzymywać żadnych zasobów przy życiuClose()
, ale mogą ustawić flagę,Dispose()
aby wyraźnie zabronić ponownego otwierania.Kontrakt for
IDisposable.Dispose
wyraźnie wymaga, aby wywołanie go na obiekcie, który nigdy nie zostanie ponownie użyty, będzie w najgorszym przypadku nieszkodliwe, dlatego zalecałbym wywołanie jednej z nichIDisposable.Dispose
lub metody wywoływanejDispose()
na każdymIDisposable
obiekcie, niezależnie od tego, czy wywoływana jest równieżClose()
.źródło
To jest stare pytanie, ale możesz teraz pisać przy użyciu instrukcji bez konieczności blokowania każdego z nich. Zostaną one usunięte w odwrotnej kolejności po zakończeniu bloku zawierającego.
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/propiments/csharp-8.0/using
źródło