Правилно ли е да се върне метод в израз за използване (обект, който имплементира iDisposable)?

Възможен дубликат:
Ако върна стойност вътре в използващ блок в метод, използването изхвърля ли обекта преди връщането?

Имам този код (опростен):

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 във финалния блок.

Така че, ако искате да върнете състоянието на операция и 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 е, че той автоматизира изхвърлянето на обект, дори ако необработено изключение е хвърлено от използващия блок.

Следователно, след като вашият код излезе от използващия блок, независимо дали се връща или по друг начин, обектът, който е „използван“, се изхвърля.

person Rich Turner    schedule 12.01.2013
comment
Отбележете също, че поради това не е необходимо да извиквате Close() изрично, както сте направили. Ако декомпилирате OleDbConnection, ще видите, че Dispose извиква Close - person Rhumborl; 12.01.2013
comment
@Rhumborl: благодаря за съвета. Дойдох от неуправляем свят (VB6 C++), така че лесно се бъркам с нещата от Garbage Collector. - person Broken_Window; 12.01.2013
comment
Y3L1NNa - Получавате +1 поне за използване. Забравете най-много от всичко, което сте знаели за VB и C++ и оставете C#/NET да стои сам по себе си. По-късно можете да сравните и оцените VB и C++, след като свикнете с парадигмата „управляван код, управлявани данни“. Честито кодиране - person Michael Viktor Starberg; 12.01.2013

Напълно безопасно е да се върнете по време на израз за използване поради магията на .NET за автоматично обработване на изхвърлянето на обекти. Цялата идея е, че не е нужно да мислите как да излезете от използващия блок, просто знаете, че когато го напуснете, обектът ще бъде изхвърлен правилно. Поради това вашият пример може да бъде опростен до това:

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