2009-12-11 13 views
20

Normalerweise schreibt man Code so, um einige Daten mit einem WebRequest herunterzuladen.Wie wird eine WebResponse-Instanz ordnungsgemäß beseitigt?

using(WebResponse resp = request.GetResponse()) // WebRequest request... 
    using(Stream str = resp.GetResponseStream()) 
     ; // do something with the stream str 

Wenn nun ein WebException geworfen wird, hat die WebException einen Verweis auf das WebResponse Objekt, das Entsorgen genannt kann oder auch nicht hat (je nachdem, wo die Ausnahme geschehen ist, oder wie die Response-Klasse implementiert) - Ich weiß es nicht.

Meine Frage ist, wie man damit umgehen soll. Soll man sehr defensiv codieren und die Antwort im WebException-Objekt ablegen (das wäre ein bisschen komisch, da WebException nicht IDisposable ist). Oder soll man das ignorieren, möglicherweise auf ein entsorgtes Objekt zugreifen oder niemals ein IDisposable-Objekt entsorgen? Das Beispiel in der MSDN-Dokumentation für WebException.Response ist völlig unzureichend.

+0

Wäre nützlich, wenn Sie "WebException.Response" im Fragentitel erwähnt haben. – Deantwo

Antwort

2

Ich bin ziemlich sicher, dass, wenn Sie eine using-Anweisung haben, das Objekt entsorgt wird, unabhängig davon, wie Sie den using-Block verlassen (sei es durch Ausnahme, Rückkehr oder einfach durch die Funktion).

Ich vermute, Sie werden feststellen, dass das Objekt innerhalb der WebException bereits entsorgt wurde, wenn Sie den using-Block verlassen.

Denken Sie daran, dass die Entsorgung eines Objekts den späteren Zugriff nicht unbedingt verhindert. Es kann unvorhersehbar sein, Methoden später aufzurufen, was zu Ausnahmen des eigenen oder sehr seltsamen Verhaltens führt (und daher würde ich es nicht empfehlen). Aber selbst ein großer Teil des Objekts bleibt für den Müllsammler zurück, selbst wenn Sie es entsorgen und daher immer noch zugänglich sind. Der Zweck der Verfügung besteht in der Regel darin, Resource-Handles zu bereinigen (wie in diesem Fall aktive TCP-Verbindungen), die Sie aus Leistungsgründen nicht realistisch herumliegen lassen können, bis der Garbage Collector sie findet. Ich erwähne dies nur, um zu verdeutlichen, dass es sich nicht gegenseitig ausschließt und dass die Ausnahme einen Verweis darauf enthält.

+0

In der Tat. 'using' ist syntaktischer Zucker für try {} finally {}, und das Objekt wird immer im finally-Block angeordnet. –

+1

Wie wäre es mit einer Ausnahme in GetResponse? Das Ergebnis wird nicht der resp-Variablen zugewiesen, also vom Ausdruck zurückgegeben und somit von der using-Anweisung entsorgt. Ich verstehe, dass man auf ein entsorgtes Objekt zugreifen kann, aber man sollte es nicht wirklich tun. Wenn dies die Absicht dieser API ist, ist die API nicht "schlecht" entworfen? – Marcus

+0

Nein, wenn GetResponse wirft kein Objekt wird entsorgt. Aber Sie können nicht wissen, ob ein Objekt erstellt wurde, da nur die Interna von GetResponse das wissen, also ist GetResponse dafür verantwortlich, sicherzustellen, dass es in dieser Situation kein Leck gibt. – erikkallen

0

Eine sehr interessante Frage (obwohl erwähnenswert ist, dass das WebResponse-Objekt entsorgt wurde, als Sie die Verwendung beenden). Mein Bauchgefühl ist, dass es nicht wirklich wichtig ist, dass Sie einen Verweis auf dieses entsorgte WebResponse-Objekt haben, solange Sie nicht versuchen, irgendetwas damit zu tun.

Sie können wahrscheinlich zugreifen noch bestimmte Eigenschaften für die Instanz zur Protokollierung (wie die ResponseUri), ohne dass ein ObjectDisposedException zu bekommen, aber insgesamt Referenz durch die Ausnahme gehalten ist nicht da, so dass Sie die Instanz weiter verwenden.

Ich würde mich interessieren zu sehen, was andere sagen.

4
using (var x = GetObject()) { 
    statements; 
} 

ist (fast) entspricht

var x = GetObject(); 
try { 
    statements; 
} 
finally { 
    ((IDisposable)x).Dispose(); 
} 

so Ihr Objekt wird immer entsorgt werden.

Dies bedeutet, dass in Ihrem Fall

try { 
    using (WebResponse resp = request.GetResponse()) { 
     something; 
    } 
} 
catch (WebException ex) { 
    DoSomething(ex.Response); 
} 

ex.Response wird das gleiche Objekt wie die lokale bzw. Objekt sein, das angeordnet ist, wenn Sie an den catch-Handler bekommen. Dies bedeutet, dass DoSomething ein Disposed-Objekt verwendet und wahrscheinlich mit einer ObjectDisposedException fehlschlägt.

+0

Wenn die Ausnahme in 'GetResponse' geworfen wird, gilt die' using'-Anweisung hier nicht, da die Ausnahme vor dem 'try' -' finally'-Block geworfen wird. Ich denke nicht, dass die Antwort bereits im "Fang" -Block liegt. – ventiseis

15

Ich habe einen kurzen Blick mit Reflektor hatte, und kann jetzt sagen:

  • WebResponse, eine abstrakte Klasse ist, die Delegierten alle seine Schließ-/Entsorgung Verhalten seiner abgeleiteten Klassen.
  • HttpWebResponse, da die abgeleitete Klasse, die Sie hier fast sicher verwenden, in ihren close/dispose-Methoden nur den tatsächlichen Antwortstrom zu entsorgen hat. Der Rest des Klassenzustands kann der zarten Gnade des GC überlassen werden.

Daraus folgt, dass es wahrscheinlich ist sicher zu tun, was Sie in Bezug auf die Ausnahmebehandlung mögen, solange:

  • Wenn Sie den Antwortstream von WebResponse im try Block lesen, muss er in ein using Block.
  • Wenn Sie den Antwort-Stream von WebException im catch Block lesen, schließen Sie es in einem using Block als auch.
  • Es besteht keine Notwendigkeit, sich über die Entsorgung von WebException selbst zu sorgen.
0

Ich bekomme ähnliche Fälle in EF DB-Verbindungen.

Also ich tatsächlich eine Verbindungsliste erstellen.

Am Ende des Spiels, ich Schleife alle von ihnen.

2

HttpWebRequest intern macht einen Speicher, um den zugrunde liegende Netzwerk Strom Strom aus, bevor WebException werfen, so dass es keine nicht verwalteten Ressource mit den von WebException.Response zurück WebResponse verbunden.

Dies macht es unnötig, Dispose() darauf anzurufen. In der Tat kann der Versuch, WebException.Response zu entsorgen, Kopfschmerzen und Probleme verursachen, weil Sie möglicherweise Anrufer Ihres Codes haben, der versucht, die damit verbundenen Eigenschaften zu lesen.

Es ist jedoch eine gute Praxis, dass Sie alle IDisposable Objekte, die Sie besitzen, entsorgen müssen. Wenn Sie sich dafür entscheiden, stellen Sie sicher, dass Sie keinen Code haben, der davon abhängig ist, dass Sie WebException.Response Eigenschaften und/oder seinen Stream lesen können. Der beste Weg wäre, die Exception zu behandeln und einen neuen Typ von Exception auszulösen, damit Sie WebException nicht an den Anrufer weitergeben, wenn dies möglich ist.

Und auch in Betracht ziehen, zu HttpClient zu verschieben, das HttpWebRequest ersetzt.

Haftungsausschluss: Keine Gewährleistung impliziert.

+0

Gleiche Antwort, aber besser: https://Stackoverflow.com/a/43131178/5815327 – Deantwo

Verwandte Themen