Подтвердить что ты не робот

SqlConnection SqlCommand SqlDataReader IDisposable

SqlConnection, SqlCommand и SqlDataReader все реализуют интерфейс IDisposable. Я прочитал о лучшей практике, чтобы всегда заключать IDisposables в блок using.

Итак, мой общий сценарий для запроса данных будет выглядеть примерно так (в лучшем случае, конечно, инструмент сопоставления, такой как linq2sql, был бы подходящим, но просто предположим, что мы хотим использовать этот подход здесь):

using (SqlConnection cn = new SqlConnection("myConnectionstring"))
{
    using (SqlCommand cm = new SqlCommand("myQuery", cn))
    {
        // maybe add sql parameters
        using (SqlDataReader reader = cm.ExecuteReader())
        {
             // read values from reader object
             return myReadValues;
        }
    }
}

Правильно ли это или можно считать излишним? Я немного не уверен в этом уровне вложенных блоков using, но, конечно, я хочу сделать это правильно. Спасибо!

4b9b3361

Ответ 1

Это 100% правильный путь. Если класс использует IDisposable, он должен быть заключен в оператор using, чтобы гарантировать, что вызывается метод Dispose(). Кроме того, общение с внешней технологией, управляемой на этом SQL-сервере, не должно восприниматься легкомысленно. Объект SqlCommand реализует IDisposable по очень веской причине. Ниже приведен код Dispose() для объекта SqlCommand:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._cachedMetaData = null;
    }
    base.Dispose(disposing);
}

и, как вы можете видеть, он освобождает ссылку на объект _cachedMetaData, чтобы он тоже мог быть очищен.

Ответ 2

Вы можете использовать следующий способ типографии, чтобы получить код ближе к левому:

using (SqlConnection cn = new SqlConnection("myConnectionstring"))
using (SqlCommand cm = new SqlCommand("myQuery", cn))
using (SqlDataReader reader = cm.ExecuteReader())
{
     // read values from reader object
     return myReadValues;
}

Как уже указывалось, использование трех вложенных блоков using правильное.

Ответ 3

Это правильный путь, если вы сделаете это с читателем. Иногда вам нужно, чтобы читатель оставался открытым (может быть, ваш метод вернет его), поэтому сразу избавиться от читателя не получится. В таких случаях существует перегрузка ExecuteReader, которая может вам помочь:

var cn = new SqlConnection("myConnectionstring");
var cm = new SqlCommand("myQuery", cn);
var reader = cm.ExecuteReader(CommandBehavior.CloseConnection);
return reader;

Это приведет к открытию соединения и чтения. Когда считыватель будет закрыт/удален, он также закроет (и удалит) соединение.

using(var reader = GetReader()) //which includes the code above
{
   ...
} // reader is disposed, and so is the connection.

Ответ 4

Да, правильно. Вы можете пропустить привязки во вложенном использовании, поскольку они являются одним из утверждений, но я не чувствую, что это добавляет читаемости.

Ответ 5

Это не слишком много. Блок using является хорошей практикой, потому что он гарантирует, что будет вызван метод Dispose() объекта, даже если выбрано исключение.

Однако есть имя для такого рода вещей. Он назывался code sugar. Итак:

using (foo bar = new foo()) { //...snip }

Короткий код для:

foo bar = null;
Exception error = null;
try {
    bar = new foo();
    // ...snip
}
catch (Exception ex) {
    error = ex;
}
finally {
    if (bar != null) bar.Dispose();
    if (error != null) throw error;
}

Любая форма равна другой, они просто разные способы написать одно и то же. Другими словами, такое же различие между for и while: они делают в основном одно и то же, но используются по-разному.

using является предпочтительным, поскольку он делает код короче и читабельнее и автоматизирует удаление для вас. Что касается того, следует ли вам его использовать, не слушайте людей, которые говорят, что вы всегда должны что-то делать. Это хорошая практика, предоставленная, но зная , когда следует использовать, , почему использовать и преимущества и последствия использования или не использования, что-то стоит путь более чем что-то делает, потому что люди говорят, что вы должны.

Изменить: У ответа Eren есть пример случая, когда вы не хотите иметь блок using для reader.

Ответ 6

Я не вижу смысла использовать SqlCommand. SqlConnection и SqlDataReader должны быть удалены.

SqlConnection, потому что он не будет закрываться сам по себе, когда он выходит из области видимости.

SqlDataReader может поддерживать SqlConnection занят, пока читатель не будет закрыт.

Даже примеры MSDN не используют SqlCommand.

Ответ 7

Я не эксперт, но я знаю, что использование переведено в блок try/finally, возможно, вы можете обернуть SqlConnection, SqlCommand и SqlDataReader в уникальный try/finally

try {
     // code here with SqlConnection, SqlCommand and SqlDataReader
}
finally
{
  // Dispose call on SqlConnection, SqlCommand and SqlDataReader
 }