Где поставить try / catch при использовании IDisposable - PullRequest
5 голосов
/ 27 октября 2011

Мне только что посоветовали поместить целый блок using в try, иначе область действия using предотвратит перехват исключения. Однако не помешает ли это using правильно распорядиться ресурсами, если возникнет исключение? Если у меня есть код ниже, где я должен поставить блоки try?

using (connSQL = new SqlConnection(strConn)) 
{
    connSQL.Open();
    using (SqlCommand commSQL = new SqlCommand(strPreparedStatement, connSQL)) 
    {
        if (sqlParameters != null)
        {
            for (int i = sqlParameters.GetLowerBound(0); i <= sqlParameters.GetUpperBound(0); i++)
            {
                commSQL.Parameters.Add(sqlParameters[i]);
            }
        }
        drSQL = commSQL.ExecuteReader();
        dtReturn.Load(drSQL);

        commSQL.Parameters.Clear();
    }
}

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

Ответы [ 3 ]

9 голосов
/ 27 октября 2011

Оператор using уже предотвратит накопление соединений - он делает чистую сторону за вас, фактически являясь блоком try / finally с вызовом Dispose в блоке finally,Если вы также хотите блок try / catch, вы можете поместить его либо внутри, либо снаружи - но вы уверены, что он не должен быть на более высоком уровне?Как вы на самом деле ожидаете обработать исключение?

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

Я бы посоветовал вам также объявлять переменные внутри операторов using, чтобы вы не пытались читать их вне блока:

using (SqlConnection connSQL = new SqlConnection(strConn)) {

InВ общем, предпочитайте, чтобы ваши переменные были настолько узкими, насколько это возможно.О, и ваш SqlDataReader должен быть в выражении using тоже.В любом случае это может не иметь значения, поскольку вы закрываете соединение и команду, но я бы сделал это из принципа: он реализует IDisposable, поэтому вы должны его утилизировать.

О, и ваш путьитерации по sqlParameters довольно длинны в данный момент.foreach делает это проще, и даже если бы он не использовал for (int i = 0; i < sqlParameters.Length; i++), если бы у меня не было оснований полагать, что это не "простой" массив.

Итак, мой эквивалентный код выглядел быкак то так:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (SqlCommand command = new SqlCommand(strPreparedStatement, connection))
    {
        if (sqlParameters != null)
        {
            // If sqlParameter is an array, you can just use
            // command.Parameters.AddRange(sqlParameters) instead
            foreach (SqlParameter parameter in sqlParameters)
            {
                command.Parameters.Add(parameter);
            }
        }
        using (SqlDataReader reader = command.ExecuteReader())
        {
            DataTable table = new DataTable();
            // Perform any extra initialization here
            table.Load(reader);
            return table;
        }
    }
}
2 голосов
/ 27 октября 2011

Вам необходимо также обернуть считыватель данных в оператор использования, поскольку он является одноразовым ресурсом:

using (var connSQL = new SqlConnection(strConn)) 
using (var commSQL = connSQL.CreateCommand()) 
{
    connSQL.Open();
    commSQL.CommandText = strPreparedStatement;
    if (sqlParameters != null)
    {
        for (int i = sqlParameters.GetLowerBound(0); i <= sqlParameters.GetUpperBound(0); i++)
        {
            commSQL.Parameters.Add(sqlParameters[i]);
        }
    }
    using (var drSQL = commSQL.ExecuteReader())
    {
        dtReturn.Load(drSQL);
    }
}

Я также сделал объекты подключения, команды и средства чтения данных, локально определенные в этой области блока.

Что касается оператора try/finally, он вам больше не нужен, поскольку операторы using гарантируют, что метод Dispose будет вызываться даже в случае исключений. И этот метод для соединений и команд sql гарантирует их правильное освобождение.

1 голос
/ 27 октября 2011

Нет необходимости ставить try catch, потому что using реализует его неявно, фактически он использует try finally и уверен, что удалит объекты.

Это MSDN с использованием Sample о try catch и использовании:

{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

равно:

using (Font font3 = new Font("Arial", 10.0f),
            font4 = new Font("Arial", 10.0f))
{
    // Use font3 and font4.
}
...