MemoryStream.Close () oder MemoryStream.Dispose ()

71

Welches rufe ich an?

Ist es notwendig, beide anzurufen?

Wird der andere eine Ausnahme auslösen, wenn ich bereits einen von ihnen angerufen habe?

Ashwnacharya
quelle
Dispose () würde alles
erledigen
4
Wickeln Sie Ihre Verwendung in die Verwendung ein und machen Sie sich darüber keine Sorgen. using (var s = new MemoryStream ()) {} Siehe diese Frage: stackoverflow.com/questions/11968289/…
Randy James

Antworten:

130

Close()und Dispose()wenn man dazu aufgefordert wird MemoryStream, dient man nur dazu, zwei Dinge zu tun:

  • Markieren Sie das entsorgte Objekt, damit eine zukünftige versehentliche Verwendung des Objekts eine Ausnahme auslöst.
  • Möglicherweise 1 Release-Verweise auf verwaltete Objekte, was die Arbeit des GC je nach GC-Implementierung etwas erleichtern kann. (Bei den heutigen GC-Algorithmen macht dies keinen wirklichen Unterschied, daher ist dies ein Punkt für eine akademische Diskussion und hat keine signifikanten Auswirkungen auf die reale Welt.)

MemoryStreamEs stehen keine nicht verwalteten Ressourcen zur Verfügung, sodass Sie diese technisch nicht entsorgen müssen. Der Effekt, a nicht zu entsorgen, MemoryStreamist ungefähr der gleiche wie das Löschen eines Verweises auf a byte[]- der GC bereinigt beide auf die gleiche Weise.

Welches rufe ich an? Ist es notwendig, beide anzurufen?

Die Dispose()Methode der Streams wird direkt an die Close()Methode 2 delegiert , sodass beide genau dasselbe tun.

Wird der andere eine Ausnahme auslösen, wenn ich bereits einen von ihnen angerufen habe?

In der Dokumentation wirdIDisposable.Dispose() ausdrücklich angegeben, dass es sicher ist Dispose(), jedes Objekt 3 mehrmals aufzurufen . (Wenn dies für eine bestimmte Klasse nicht zutrifft, implementiert diese Klasse die IDisposableSchnittstelle auf eine Weise, die gegen ihren Vertrag verstößt, und dies wäre ein Fehler.)

Das alles zu sagen: Es macht wirklich keinen großen Unterschied, ob Sie einen entsorgen MemoryStreamoder nicht. Der einzige wirkliche Grund, warum es Close/ DisposeMethoden hat, ist, dass es von erbt Stream, was erfordert, dass diese Methoden als Teil seines Vertrags Streams unterstützen, die nicht verwaltete Ressourcen haben (wie Datei- oder Socket-Deskriptoren).


1 Die Implementierung von Mono gibt die byte[]Referenz nicht frei . Ich weiß nicht, ob die Microsoft-Implementierung dies tut.

2 "Diese Methode ruft Close auf, das dann Stream.Dispose (Boolean) aufruft."

3 "Wenn die Dispose-Methode eines Objekts mehrmals aufgerufen wird, muss das Objekt alle Aufrufe nach dem ersten ignorieren."

cdhowie
quelle
Beachten Sie, dass der Teil über das Entsorgen MemoryStream, der die Arbeit des GC erleichtert, nur gilt, wenn Sie aus irgendeinem Grund einen Verweis auf das entsorgte Stream-Objekt hatten.
Edward Brey
@ EdwardBrey True. Dies hängt von der GC-Implementierung ab. Alle gängigen CLR-Implementierungen verwenden heutzutage eine Variante des Mark-and-Sweep-GC. Es handelt sich also wirklich um eine akademische Diskussion - die heutigen GCs zeigen keinen Unterschied.
CDhowie
3
In Bezug auf Ihre Fußnote 1gibt laut .NET-Referenzquelle .Dispose() auch die interne byte[]nicht frei. Die einzige Ressource, die festgelegt nullwird _lastReadTask, wird nur in der Methode verwendet Task<int> ReadAsync(byte[], int, int, CancellationToken). Neben Einstellung , dass eine Variable null alle ist es gesetzt _isOpen, _writableund _expandablezu false.
Scott Chamberlain
10

Nichts des oben Genannten. Sie müssen weder anrufen Closenoch Dispose.

MemoryStreamenthält keine nicht verwalteten Ressourcen, daher ist die einzige Ressource, die zurückgefordert werden kann, Speicher. Der Speicher wird während der Speicherbereinigung mit dem Rest des MemoryStreamObjekts zurückgefordert, wenn Ihr Code nicht mehr auf das verweist MemoryStream.

Wenn Sie einen langlebigen Verweis auf das haben MemoryStream, können Sie diesen Verweis auf null setzen, damit der MemoryStreamMüll gesammelt werden kann. Closeund Disposebefreien Sie weder den Dampfpuffer noch das MemoryStreameigentliche Objekt.

Da weder ein Finalizer Streamnoch MemoryStreamein Finalizer vorhanden sind, müssen Sie nicht aufrufen Closeoder aufrufen lassen Dispose, GC.SuppressFinalizeum die Speicherbereinigung zu optimieren. Es gibt keinen zu unterdrückenden Finalizer.

In den Dokumenten für MemoryStream heißt es:

Dieser Typ implementiert die IDisposableSchnittstelle, verfügt jedoch nicht über Ressourcen, die entsorgt werden müssen. Dies bedeutet, dass das Entsorgen durch direktes Aufrufen Dispose()oder Verwenden eines Sprachkonstrukts wie using(in C #) oder Using(in Visual Basic) nicht erforderlich ist.

Edward Brey
quelle
8

Sie können den usingBlock dafür verwenden. Es wird automatisch aufgerufen, Disposewenn es außerhalb seines Bereichs liegt.

Beispiel:

using (MemoryStream ms = new MemoryStream())
{
    // Do something with ms..
}
// ms is disposed here

Hoffe das hat geholfen.

Kevin
quelle
7

Verwenden Sie usingblock, damit Ihr Objekt entsorgt wird, wenn es die IDisposableSchnittstelle implementiert

TalentTuner
quelle
5

Welches rufe ich an?

Jeder von ihnen.

Ist es notwendig, beide anzurufen?

Nein, beides ist ausreichend.

Wird der andere eine Ausnahme auslösen, wenn ich bereits einen von ihnen angerufen habe?

Nein, das Einwegmuster erklärt, dass nachfolgende Aufrufe von Dispose keine negativen Auswirkungen haben.

QrystaL
quelle
Ich habe dies gerade in einer Live-Anwendung durchlaufen. Schließen und Entsorgen verhalten sich in CLR 4.5 anders. Dispose sollte ausreichend sein, aber Sie können Close und dann Dispose aufrufen, wenn Sie möchten.
Rkralston
4

Der folgende Code ist Stream.Dispose vom Reflektor, wie Sie sehen können, müssen Sie nicht schließen, wenn Sie entsorgen (was bei Verwendung von implizit ist)

public void Dispose()
{
    this.Close();
}
vc 74
quelle
3

Wenn Sie Close () aufrufen, wird Dispose () intern aufgerufen, um die Ressourcen freizugeben.

Weitere Informationen finden Sie unter diesem Link: msdn

Hps
quelle
1

Nur anrufen reicht aus Dispose()=)

Singleton
quelle
1

In .NET 3.5 (andere Versionen wurden nicht überprüft) werden Methoden beim Entsorgen eines MemoryStream in der folgenden Reihenfolge aufgerufen:

  1. Stream.Dispose ()
    • ruft einfach Close auf
  2. Stream.Close ()
    • ruft Dispose (true) auf, dann GC.SuppressFinalize (this)
  3. MemoryStream.Dispose (true)
    • setzt die Flags _isOpen, _writable und _expandable auf false
  4. Stream.Dispose (true)
    • Schließt das asynchrone Ereignis, wenn es aktiv ist
Tor Langlo
quelle
0

Als erste Lösung wird empfohlen, wo immer möglich Anweisungen zu verwenden. Dies wird hier beschrieben: http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Wenn die Lebensdauer eines IDisposable-Objekts auf eine einzelne Methode beschränkt ist, sollten Sie es in der using-Anweisung deklarieren und instanziieren. Die using-Anweisung ruft die Dispose-Methode für das Objekt auf die richtige Weise auf und bewirkt (wenn Sie sie wie oben gezeigt verwenden), dass das Objekt selbst den Gültigkeitsbereich verlässt, sobald Dispose aufgerufen wird. Innerhalb des using-Blocks ist das Objekt schreibgeschützt und kann nicht geändert oder neu zugewiesen werden.

Wenn wir jetzt zu der Frage kommen, wie andere in den meisten .NET Framework-Klassen vorgeschlagen haben, gibt es keinen Unterschied zwischen Close () und Dispose (), und es spielt keine Rolle, welche der beiden Methoden Sie aufrufen. Sie sollten einen anrufen, aber nicht beide. Es gibt jedoch Ausnahmen .

Es gibt Ausnahmen; Beispielsweise haben System.Windows.Forms.Form und System.Data.SqlClient.SqlConnection ein unterschiedliches Verhalten für Close () und Dispose ().

Ausführliche Informationen finden Sie hier: https://blogs.msdn.microsoft.com/kimhamil/2008/03/15/the-often-non-difference-between-close-and-dispose/

sin2akshay
quelle