[英]How does WebResponse not have “Dispose” publically visible when it implements IDisposable?
[英]How to properly dispose of a WebResponse instance?
通常,使用WebRequest編寫類似這樣的代碼來下載一些數據。
using(WebResponse resp = request.GetResponse()) // WebRequest request...
using(Stream str = resp.GetResponseStream())
; // do something with the stream str
現在,如果拋出WebException,WebException會引用WebResponse對象,該對象可能會或可能不會調用Dispose(取決於發生異常的位置,或者響應類的實現方式) - 我不知道。
我的問題是如何處理這個問題。 是否應該編寫一個非常防御性的編碼,並在WebException對象中處理響應(這有點奇怪,因為WebException不是IDisposable)。 或者是否應該忽略這一點,可能訪問已處置的對象或從不處置IDisposable對象? WebException.Response的MSDN文檔中給出的示例完全不合適。
我已經快速瀏覽了Reflector,現在可以說:
WebResponse
是一個抽象類,它將所有關閉/處理行為委托給它的派生類。 HttpWebResponse
,作為你幾乎肯定在這里使用的派生類,在它的close / dispose方法中,只關心處理實際的響應流。 其余的階級國家可以留給GC的招標憐憫。 因此,只要符合以下條件,就異常處理做任何你喜歡的事情都可能是安全的:
try
塊中的WebResponse
讀取響應流時,將其包含在using
塊中。 catch
塊中的WebException
讀取響應流,也將它包含在using
塊中。 WebException
本身。 using (var x = GetObject()) {
statements;
}
是(幾乎)相當於
var x = GetObject();
try {
statements;
}
finally {
((IDisposable)x).Dispose();
}
所以你的對象將永遠處理掉。
這意味着在你的情況下
try {
using (WebResponse resp = request.GetResponse()) {
something;
}
}
catch (WebException ex) {
DoSomething(ex.Response);
}
ex.Response將是與本地resp對象相同的對象,當你到達catch處理程序時它會被釋放。 這意味着DoSomething正在使用已處置的對象,並且可能會因ObjectDisposedException而失敗。
我很確定當你有一個using語句時,無論你如何退出using塊(無論是通過異常,返回還是只是通過函數進行),都會釋放對象。
我懷疑如果讓它離開使用塊,你會發現WebException中的對象已被處理掉了。
請記住,處置對象不一定會阻止以后訪問它。 嘗試稍后調用方法可能是不可預測的,導致它自己或非常奇怪的行為的異常(因此我不推薦它)。 但即使你丟棄它,即使仍然有很大一部分對象仍留在垃圾收集器中,因此仍可訪問。 dispose的目的通常是清理資源句柄(就像在這種情況下是活動的TCP連接),出於性能原因,在垃圾收集器找到它們之前,您無法實際放置。 我只是提到這一點,以澄清它的處理並不是相互排斥的,而是提及它的例外情況。
在拋出WebException
之前, HttpWebRequest
內部使內存流脫離底層網絡流,因此沒有與WebException.Response
返回的WebResponse
關聯的非托管資源。
這使得不必在其上調用Dispose()
。 實際上,嘗試處置WebException.Response
可能會導致頭痛和問題,因為您的代碼調用者可能會嘗試讀取與之關聯的屬性。
但是,您應該處置您擁有的任何IDisposable
對象是一個好習慣。 如果您決定這樣做,請確保您沒有代碼,具體取決於能否讀取WebException.Response
屬性和/或其流。 最好的方法是處理異常並拋出新類型的異常,以便在可能的情況下不會將WebException
泄漏給調用者。
並且還考慮轉移到替換HttpWebRequest
HttpClient
。
免責聲明:不提供任何保證。
一個非常有趣的問題(雖然值得指出,當您退出使用時,WebResponse對象將被處理掉)。 我的直覺是,只要您不嘗試對其進行任何“操作”操作,您就可以引用此處理的WebResponse對象並不重要。
您可能仍然可以訪問實例上的某些屬性以進行日志記錄(例如ResponseUri)而不會收到ObjectDisposedException
,但異常所持有的整體引用不存在,因此您可以繼續使用該實例。
我有興趣看看別人怎么說。
我在EF DB連接中遇到類似的情況。
所以我實際上創建了一個連接列表。
在游戲結束時,我循環處理所有這些。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.