Эта функция правильно высвобождает ресурсы? - PullRequest
0 голосов
/ 23 сентября 2010

Я пытаюсь убедиться, что я не оставляю открытые концы в своем приложении открытыми и беспокоюсь о некоторых, но могу получить ответ из этого.Я «переопределил» некоторые функции, чтобы я мог стараться сохранять все ресурсы максимально чистыми и свободными.Так что в этом случае у меня есть функция с именем 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 заявление.Кроме того, я не уверен, должна ли это быть вики сообщества или нет.Если это так, дайте мне знать.Спасибо.

Обновление кода :

Вот пример того, как я его использую.

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, которую будет одновременно использовать только один пользователь (небольшое приложение с очень-очень малой вероятностью, что оно будет расти), поэтому я не думал, что необходимо все время закрывать и открывать соединение.Может я не прав, не уверен.Используя его таким образом, он потенциально пригоден для очистки ресурсов?

Ответы [ 2 ]

3 голосов
/ 23 сентября 2010

Передача DbDataReader плохая идея, так как для этого необходимо, чтобы поток оставался открытым, и для правильного выполнения вызова используется код, который освобождает читателя. Это также затрудняет закрытие базовых объектов команд и соединений. Один из способов облегчить это, если вы действительно хотите выставить читателя, - это использовать CommandBehavour. Это можно использовать для закрытия основного соединения, когда сам ридер закрыт.

dbCommand.ExecuteReader(CommandBehavour.CloseConnection)

Поскольку DbConnection, DbCommand и DbDataReader являются одноразовыми, вам необходимо провести рефакторинг кода, чтобы его можно было очистить после завершения работы с ним. Одним из способов достижения этого является реализация IDisposable в вашем собственном классе и удаление пузырьков для любых инкапсулированных объектов. Вызывающий код может затем реализовать использование для обеспечения освобождения ресурсов.

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 голосов
/ 23 сентября 2010

Возвращение экземпляра IDisposable из функции совершенно нормально.Владение экземпляром передается из функции вызывающей стороне, и теперь вызывающая сторона отвечает за вызов Dispose.Это тот же принцип в игре, когда вы звоните IDbCommand.ExecuteReader.

Вы обязательно должны использовать оператор Using.Это делает код более читабельным, поскольку он автоматически вставляет правильный блок try-finally, который вызывает метод Dispose.Я не знаю деталей проблемы, на которую вы ссылались, но у вас самих не должно быть проблем, поскольку вы не делаете ничего необычного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...