Использует ли оператор С# выполнение try/finally?

Предположим, что у меня есть следующий код:

private void UpdateDB(QuoteDataSet dataSet, Strint tableName)
{
    using(SQLiteConnection conn = new SQLiteConnection(_connectionString))
    {
        conn.Open();
        using (SQLiteTransaction transaction = conn.BeginTransaction())
        {
            using (SQLiteCommand cmd = new SQLiteCommand("SELECT * FROM " + tableName, conn))
            {
                using (SQLiteDataAdapter sqliteAdapter = new SQLiteDataAdapter())
                {
                    sqliteAdapter.Update(dataSet, tableName);
                }
            }
            transaction.Commit();
        }
    }
}

В документации на С# указано, что с помощью оператора using объект в пределах области будет удален, и я видел несколько мест, где он предположил, что нам не нужно использовать предложение try/finally.

Я обычно окружаю свои связи с помощью try/finally, и я всегда закрываю соединение в предложении finally. Учитывая приведенный выше код, разумно ли предположить, что соединение будет закрыто, если есть исключение?

Ответы

Ответ 1

Вы правы; оператор using компилируется в блок try/finally.

Компилятор преобразует using(resource) statement; в следующий код:

{
   ResourceType resource = expression;
   try {
      statement;
   }
   finally {
      if (resource != null) ((IDisposable)resource).Dispose();
   }
}

(Приведение в IDisposable в том случае, если ResourceType явно реализует IDisposable.

Ответ 2

Да, вам либо нужно использовать оператор try/finally или using. Вам не нужны оба.

A using statement почти то же самое, что и try/finally, за исключением того, что в С# 3 вы не можете переназначить переменную внутри использования блок.

using (IDisposable d = foo())
{
     d = null; // Error:  Cannot assign to 'd' because it is a 'using variable'
}

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

Возможно, некорректное присвоение локальному 'd', который является аргументом для оператора use или lock. Вызов Dispose или разблокировка произойдет при исходном значении локального.

Ответ 3

Да, оператор using в значительной степени просто сокращает блок try ... finally.

Например, этот код...

using (MyDisposableType foo = new MyDisposableType())
{
    foo.DoSomething();
}

... приравнивается к следующему...

{
    MyDisposableType foo = new MyDisposableType();
    try
    {
        foo.DoSomething();
    }
    finally
    {
        if (foo != null)
            ((IDisposable)foo).Dispose();
    }
}

Ответ 4

Можно предположить, что соединение будет закрыто, если вы получите исключение.

Ответ 5

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