2009-12-11 66 views
20

通常情況下,用這樣的代碼編寫代碼來使用WebRequest下載一些數據。如何正確處置WebResponse實例?

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

現在,如果引發WebException,所述引發WebException具有對WebResponse對象,其可以是或可以不是已處置稱爲(取決於異常已經發生,或響應類是如何實現的)的參考 - 我不知道。

我的問題是如何處理這個問題。是否應該在防守方面進行編碼,並將響應置於WebException對象中(這會有點奇怪,因爲WebException不是IDisposable)。還是應該忽略這一點,可能訪問一個處置對象或永遠不處理一個IDisposable對象? WebException.Response的MSDN文檔中給出的示例完全不適用。

+0

如果您在問題標題中提到了「WebException.Response」,它會很有用。 – Deantwo 2018-02-26 08:12:12

回答

2

我非常確定,當你有一個using語句時,對象被處置,而不管你如何退出using塊(通過異常,返回或簡單地通過函數)。

我懷疑你會發現WebException中的對象已經被放置,如果你讓它離開使用塊。

請記住,處置對象不一定會阻止以後訪問它。嘗試稍後調用它的方法是不可預知的,導致它自己的或非常奇怪的行爲的異常(因此我不會推薦它)。但即使您處置垃圾收集器,仍然有很大一部分對象仍留在垃圾回收器中,因此仍然可以訪問。 dispose的目的通常是清理資源句柄(就像在這種情況下活動的TCP連接),出於性能方面的原因,在垃圾回收器找到它們之前,你不可能真正離開。我只是提到這一點,以澄清它是不是相互排斥的處置和舉例來提及它。

+0

確實。 'using'是try {{finally} {}}的合成糖,並且該對象將始終放置在finally塊中。 – 2009-12-11 11:07:05

+1

如何在GetResponse中發生異常?結果不會被分配給resp變量,因此從表達式返回,因此由using語句處理。 我明白一個人可以訪問一個處置對象,但是,其實並不是真的。如果這是api的意圖,是不是「糟糕」設計的api? – Marcus 2009-12-11 11:12:47

+0

不,如果GetResponse拋出沒有對象將被丟棄。但是由於只有GetResponse的內部知道這個對象,所以你無法知道是否創建了一個對象,所以GetResponse的責任是確保在這種情況下沒有泄漏。 – erikkallen 2009-12-11 11:16:35

0

一個非常有趣的問題(雖然值得指出的是WebResponse對象已退出使用時處置)。我的直覺是,只要你不嘗試做任何「可操作」的事情,你就可以參考這個處理過的WebResponse對象並不重要。

可以可能仍然可以訪問某些屬性上的實例進行日誌記錄(如ResponseUri)沒有得到一個ObjectDisposedException,而是由異常持有整體引用不是有那麼您可以繼續使用該實例。

我很想看看別人怎麼說的。

4
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而失敗。

+0

如果在GetResponse中引發異常,'using'語句在這裏不適用,因爲異常在'try' - finally'塊之前被拋出。我不認爲這個迴應已經在'catch'塊中處理了。 – ventiseis 2015-11-24 21:49:20

15

我有一個快速瀏覽一下與反射器,現在可以說:

  • WebResponse,是一個抽象類,代表所有的關閉/處置行爲,其派生類。
  • HttpWebResponse作爲您幾乎可以肯定在這裏使用的派生類,在它的close/dispose方法中,只關心處理實際的響應流。剩下的階級狀態可以留給GC的溫柔憐憫。

由此可見,它可能是安全的,做任何你關於異常處理等,只要:

  • 當你閱讀從WebResponsetry塊響應流,其封裝在一個using區塊。
  • 如果您在catch塊中讀取WebException的響應流,請將其也包含在using塊中。
  • 有沒有必要擔心處置WebException本身。
0

我在EF DB連接中遇到類似情況。

所以我實際上創建了一個連接列表。

在遊戲結束時,我循環處理所有這些。

2

HttpWebRequest內部使得投擲WebException前一個存儲器關閉流底層的網絡流,所以與來自WebException.Response返回的WebResponse相關聯的非託管資源。

這使得它不必調用Dispose()就可以了。事實上,試圖處置WebException.Response可能會導致頭痛和問題,因爲您可能有代碼的調用者嘗試讀取與其關聯的屬性。

但是,您應該丟棄您擁有的任何IDisposable對象,這是一種很好的做法。如果您決定這樣做,請確保您沒有代碼,具體取決於是否能夠讀取WebException.Response屬性和/或其流。最好的方法是處理異常並拋出新類型的異常,以便在可能的情況下不會將WebException泄露給調用者。

並且還考慮移動到HttpClient,其取代HttpWebRequest

免責聲明:不保證。

+0

同樣的答案,但更好:https://stackoverflow.com/a/43131178/5815327 – Deantwo 2018-02-26 08:16:28