2010-09-23 36 views
0

我試圖確保我不會在應用程序中留下任何鬆散的末端,並且擔心一些問題,但可能會從我的答案中得到答案。我已經「覆蓋」了一些功能,這樣我就可以嘗試儘可能保持所有資源的清潔和免費。所以在這個例子中,我有一個叫ExecuteReader的函數,它正常地返回一個DbDataReader,但我必須傳遞給它的是一個SQL字符串,而不是每次都重新創建一個DbCommand。我想確保即使我無法致電dbCommand.Dispose()它實際上是這樣做的。任何和所有的幫助表示讚賞。此功能是否正確釋放資源?

Public Function ExecuteReader(ByVal strSQL As String) As DbDataReader 
    Dim dbCommand = _dbConnection.CreateCommand() 
    dbCommand.CommandText = strSQL 
    dbCommand.Prepare() 
    Return dbCommand.ExecuteReader() 
End Function 

我想用using說法,但我記得看到一個線程如果有人說,他們認爲這是造成他們有在using聲明回報問題。另外,我不確定這是否應該是社區wiki。如果應該的話,讓我知道。謝謝。

代碼更新

這裏是我如何使用它的例子。

Public Sub RevertDatabase() 
    'This function can be used whenever all changes need to be undone, but was created' 
    'for saving the data as a .out file. It sets all changes back to their original value.' 

    'Set the data reader to all parts and columns that were changed.' 
    _dbReader = ExecuteReader("SELECT PART_ID, PART_PREV_VALUE, REPORT_COLUMN_NAME FROM REPORTS WHERE PART_PREV_VALUE NOT NULL") 
    'Create an instance of the Command class.' 
    Dim cmd = New Command() 

    While _dbReader.Read() 
     'For each part and columns that has been changed, set the values in the' 
     'new cmd variable and then update the value using the same function' 
     'that is used whenever a value is changed in the data grid view.' 
     cmd.CommandString = _dbReader("REPORT_COLUMN_NAME").ToString().Replace("_", " ") 
     cmd.Value = _dbReader("PART_PREV_VALUE").ToString() 
     cmd.ID = _dbReader("PART_ID").ToString() 
     UpdateValue(cmd) 
    End While 

    'Close the reader.' 
    _dbReader.Close() 
End Sub 

在這裏,我將_dbReader設置爲我從函數中得到的內容,並最終關閉了_dbReader。我不關閉連接,因爲每次查詢時都不打開它。這是一個SQLite數據庫,一次只能有一個用戶使用(小應用程序的可能性會越來越小),所以我不認爲有必要一直關閉和打開連接。也許我錯了,不確定。用這種方式,它可能可以清潔資源嗎?

回答

3

傳回DbDataReader是一個壞主意,因爲這需要流保持打開狀態,並依靠調用代碼來通過配置讀取器來執行正確的操作。這也使得很難關閉底層的命令和連接對象。如果你真的想要公開讀者,一種方法是使用CommandBehavour。當閱讀器本身關閉時,這可用於關閉底層連接。

dbCommand.ExecuteReader(CommandBehavour.CloseConnection) 

作爲的DbConnection,DbCommand和和DbDataReader都是一次性的,你需要重構代碼,以允許這些被清理,當代碼已經與他們完成。一種方法是實現這一點,就是在你自己的類中實現IDisposable,並且將bubble放置到任何封裝對象中。調用代碼然後可以實現使用以確保資源被釋放。

Using helper As New DatabaseHelper() 
    Using reader As IDataReader = helper.LoadSomeDataReader() 

     ' do something with reader 

    End Using 
End Using 

UPDATE:

你的代碼的第二塊會變得越來越像:

Public Sub RevertDatabase() 
    Using _dbReader As IDataReader = ExecuteReader(...) 

     While _dbReader.Read() 

     Using cmd As New Command() 
      cmd.CommandString = _dbReader("REPORT_COLUMN_NAME").ToString().Replace("_", " ") 
      cmd.Value = _dbReader("PART_PREV_VALUE").ToString() 
      cmd.ID = _dbReader("PART_ID").ToString() 
      UpdateValue(cmd) 
     End Using 

     End While 

    End Using 
End Sub 

你應該總是打開和關閉連接,而並非只是任由。這是可以實踐的,儘管在一個非常小的應用程序中可能性很小,但您可能會遇到問題。你也不應該保留對_dbReader IMO的引用。

+0

檢查我更新的代碼。我想我應該說明我是如何使用它來查看是否仍然不安全。感謝你的回答。 – XstreamINsanity 2010-09-23 13:37:15

+0

是的,在我發表了關於不需要打開和關閉它的帖子後,我想我會測試打開它需要多長時間,並且不需要很長時間,所以我也可以。我感謝您的答覆,並會盡力實施,無論我在哪裏使用它。 – XstreamINsanity 2010-09-23 14:21:28

0

從函數返回一個IDisposable實例是非常好的。實例的所有權正在從功能轉移給呼叫者,現在呼叫者有責任撥打Dispose。打電話給IDbCommand.ExecuteReader時,這與確切的相同。

您一定要使用Using聲明。它使代碼更具可讀性,因爲它會自動插入調用Dispose方法的正確try-finally塊。我不知道你提到的問題的細節,但你不應該有任何問題,因爲你沒有做任何不尋常的事情。

Public Sub RevertDatabase() 
    Using dbReader As DbDataReader = ExecuteReader(...) 
     // Use the data reader here. 
    End Using 
End Sub