Размещение обработки исключений - C # - PullRequest
3 голосов
/ 04 апреля 2011

Я решил удалить некоторые из операторов using в моем коде, чтобы я мог перехватить определенные исключения и обработать удаление ресурсов вручную.Я произвел рефакторинг некоторого кода, чтобы сделать его более читабельным и понятным, после реализации нового блока try / catch мне остается только задаться вопросом, правильно ли они были размещены для текущей задачи.

Пример:

public static DataTable Select(string table, string[] column, Object operand)
{
        DataTable dTable = null;
        SQLiteConnection connection = null;
        SQLiteCommand command = null;
        SQLiteDataReader dReader = null;

        //convert to array for arguments
        StringBuilder query = new StringBuilder();
        query.Append("select ");

        for (int i = 0; i < column.Length; i++)
        {
            query.Append(column[i]);

            if (i < column.Length - 1)
            {
                query.Append(",");
            }
        }
        query.Append(" from ");
        query.Append(table);

        try
        {
            connection = new SQLiteConnection(_connectionString);
            command = new SQLiteCommand(query.ToString(), connection);
            dTable = new DataTable();

            connection.Open();

            dReader = command.ExecuteReader();

            dTable.Load(dReader);

            return dTable;
        }
        catch (SQLiteException sqle)
        {
            //Handle exception
        }
        finally
        {
            connection.Dispose();
            command.Dispose();
            dReader.Dispose();
            dTable.Dispose();
        }
        return null;
}

В этом примере я реализовал попытку / перехват только для самих операций SQL, я сделал это, поскольку он гарантирует, что любые исключения, которые выдают, могут быть отмечены, а ресурсы распределены правильно.Затем я заметил, что это оставило цикл for открытым для исключений, хотя поставляемый индексатор будет защищен и создан с помощью графического интерфейса.

Было бы целесообразно инкапсулировать весь метод в операторе try / catch или ябыть слишком осторожным?Можно сказать, что я ищу лучшую практику, когда дело доходит до управления размещением самих операторов.

Спасибо за ваше время!

Редактировать:

Я знаю, что заявление об использовании было бы идеальным с точки зрения обращения с утилизацией и управлением ресурсами, однако, как уже упоминалось в начале вопроса, я хотел бы иметь возможность отлавливать конкретные типы исключений, в частности те, которые сгенерированы изКомпоненты SQLite.

Ответы [ 6 ]

9 голосов
/ 04 апреля 2011

Не забудьте null чек:

finally {
  if (connection != null) connection.Dispose();
  if (command != null) command.Dispose();
  if (dReader != null) dReader.Dispose();
  if (dTable != null) dTable.Dispose();
}

Возможно, что один из конструкторов выдает исключение, в этом случае объекты не будут инициализированы.

3 голосов
/ 04 апреля 2011

Зачем использовать try / catch явно, если вас беспокоит управление ресурсами? Используйте using вместо:

using(SQLiteConnection connection = new SQLiteConnection(_connectionString))
{ 
   ..
   using(SQLiteCommand command = new SQLiteCommand(query.ToString(), connection))
   {
      using(SQLiteDataReader  reader = dReader = command.ExecuteReader())
      {
          dTable.Load(dReader);
      }
   }
}

Также в настоящее время вы возвращаете dTable, но вы выбрасываете его в свой блок finally.

2 голосов
/ 04 апреля 2011

Вы можете заключить весь метод в try / catch, если считаете, что есть вероятность, что исключения будут выброшены за пределы проблем с базой данных.Вы можете легко дифференцировать исключения по тому, что вы ловите.Например:

DataTable dTable = null;
SQLiteConnection connection = null;
SQLiteCommand command = null;
SQLiteDataReader dReader = null;

try
{
  // non-DB code

  // DB code
}
catch (SQLiteException sqle)
{
  // Handle DB exception
}
catch (IndexOutOfRangeException ie)
{
  // If you think there might be a problem with index range in the loop, for example
}
catch (Exception ex)
{
  // If you want to catch any exception that the previous catches don't catch (that is, if you want to handle other exceptions, rather than let them bubble up to the method caller)
}
finally
{
  // I recommend doing some null-checking here, otherwise you risk a NullReferenceException.  There's nothing quite like throwing an exception from within a finally block for fun debugging.
  connection.Dispose();
  command.Dispose();
  dReader.Dispose();
  dTable.Dispose();
}
return null;
1 голос
/ 04 апреля 2011

Я не знаю, является ли это наилучшей практикой, но я обычно помещаю операторы try / catch вокруг блоков кода, к которым обращаются внешние ресурсы, такие как доступ к базе данных, файловый ввод-вывод и т. Д., Которые могут выдавать исключения по различным причинам(недоступный ресурс, ошибка ввода-вывода и т. д.).Я не защищаю код, который я контролирую - вот где начинаются модульные тесты

Кстати: вы знаете, что вы можете заменить свой цикл на string.Join()?

Обновление : просто для пояснения: блоки try / catch действительно имеют смысл, только если вы хотите перехватить конкретное исключение и выполнить некоторую пользовательскую логику.В противном случае вам следует придерживаться using и позволить исключению всплыть и обработать его в соответствующем месте (например, уведомить пользователя о том, что некоторые данные не могут быть сохранены из-за недоступности сервера или около того)

1 голос
/ 04 апреля 2011

Большую проблему, которую вы представили с помощью этого рефакторинга, можно увидеть, если подумать, что произойдет, если создание одного из промежуточных объектов не удастся. Например, если создается создание соединения, то что происходит с исключением, которое выдается в вашем блоке finally, который пытается вызвать Dispose для всех этих нулевых переменных? По крайней мере, заранее проверьте на null, или добавьте дополнительную try / catch внутри вашей версии finally. Я бы сказал, что вы могли бы извлечь выгоду из использования Resharper, который бы уже указывал на эти проблемы.

0 голосов
/ 04 апреля 2011

Если все, что вас беспокоит, это правильная утилизация вещей, вы должны использовать для этого блок «использование». http://msdn.microsoft.com/en-us/library/yh598w02.aspx

...