Правильно ли возвращать метод внутри состояния using (объект, который реализует iDisposable)?

Возможный дубликат:
Если я возвращаю значение внутри блока using в методе, удаляет ли using объект перед возвратом?

У меня есть этот код (простой):

bool method1()
{
      using (OleDbConnection con = new OleDbConnection(connString))
            {
                bool b = false;

                try
                {
                    con.Open();
                    b = true;

                }
                catch (Exception)
                {
                    b = false;
                }
                finally
                {
                    con.Close();
                    return b;
                }                
            }
}

Я возвращаюсь перед закрывающей фигурной скобкой выражения "using". Мой объект "con" все равно удаляется? Лучше использовать следующий код ?:

bool method1()
{
      bool b = false;
      using (OleDbConnection con = new OleDbConnection(connString))
            {
                try
                {
                    con.Open();
                    b = true;

                }
                catch (Exception)
                {
                    b = false;
                }
                finally
                {
                    con.Close();                    
                }                
            }

        return b;
}

person Broken_Window    schedule 12.01.2013    source источник


Ответы (5)


using расширяется до более сложного с дополнительным if оператором, например

OleDbConnection con = new OleDbConnection(connString)
try
{
    con.Open();
}
finally
{
    // Check for a null resource.
    if (con != null)
        // Call the object's Dispose method.
        ((IDisposable)con).Dispose();
}  

Итак, в вашем примере вы можете получить NullReferenceException в блоке finally.

Поэтому, если вы хотите вернуть статус операции и Dispose и объект, я предлагаю использовать этот фрагмент кода.

using(OleDbConnection con = new OleDbConnection(connString))
{
    try
    {
        con.Open();
        return true;
    }catch(OleDbException ex)
    {
        //log error
        return false;
    }
}
person Ilya Ivanov    schedule 12.01.2013
comment
Я выбрал этот вариант в качестве ответа, потому что он наиболее точен для моего конкретного случая, и я не заметил, что могу получить исключение NullReferenceException в некоторых сценариях. Спасибо! - person Broken_Window; 12.01.2013
comment
обратите внимание, чтобы не ловить Exception в блоке catch. Просто перехватите конкретные OleDbException исключения. Но в этом случае я бы подумал о том, чтобы сделать метод void и не возвращать какой-то флаг. Это делает исключение для исключительных случаев, а не для нормального потока логики. - person Ilya Ivanov; 12.01.2013

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

Следовательно, как только ваш код выходит из блока using, независимо от того, возвращается он или нет, объект, который был «использован», утилизируется.

person Rich Turner    schedule 12.01.2013
comment
Также обратите внимание, что из-за этого вам не нужно явно вызывать Close(), как вы это сделали. Если вы декомпилируете OleDbConnection, вы увидите, что Dispose вызывает Close - person Rhumborl; 12.01.2013
comment
@Rhumborl: спасибо за подсказку. Я пришел из неуправляемого мира (VB6 C ++), поэтому меня легко запутать в сборщике мусора. - person Broken_Window; 12.01.2013
comment
Y3L1NNa - Вы получаете +1 хотя бы за использование using. Забудьте больше всего, что вы знали о VB и C ++, и позвольте C # / NET оставаться сам по себе. Позже вы сможете сравнить и оценить как VB, так и C ++, как только привыкнете к парадигме «управляемый код, управляемые данные». Счастливое кодирование - person Michael Viktor Starberg; 12.01.2013

Возврат во время использования оператора является полностью безопасным из-за магии .NET, связанной с автоматической обработкой удаления объектов. Вся идея в том, что вам не нужно думать о том, как выйти из блока using, вы просто знаете, что когда вы выйдете из него, объект будет правильно расположен. По этой причине ваш пример можно упростить до следующего:

bool method1()
{
    using (OleDbConnection con = new OleDbConnection(connString))
        {
            try
            {
                con.Open();
                return true;
            }
            catch (Exception)
            {
                return false;
            }          
    }
}

con.Close () может быть удален, так как он автоматически вызывается утилизацией.

Посмотрите на это, если вы хотите увидеть, что происходит под капотом.

person Phil    schedule 12.01.2013

нет разницы между двумя участками кода; con объект будет удален в обоих примерах.

person daryal    schedule 12.01.2013

В первом примере вы устанавливаете временную переменную и возвращаете ее.

О возврате в finally: что происходит после компиляции, вы переходите к концу метода, а затем возвращаете временную переменную.

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

person atlaste    schedule 12.01.2013