Сборка мусора, стоит ли на это полагаться? - PullRequest
6 голосов
/ 23 августа 2010

В коде, скажем, у нас есть:

using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString()))
{
    cn.Open();

    // Set all previous settings to inactive
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn))
    {                            
        cmd.ExecuteNonQuery();
    }

    cn.Close();
}

cn.close технически не требуется, поскольку сборка мусора позаботится о соединении для нас.

Тем не менее, я всегда люблю закрывать его и не полагаться на сборку мусора. Это плохо? Трата времени? Или считается хорошей практикой не полагаться на автоматизацию?

Спасибо за ваши мысли и мнения заранее. Я отмечу это как вики сообщества, поскольку это, вероятно, субъективно.

Ответы [ 2 ]

15 голосов
/ 23 августа 2010

Вы никогда не должны полагаться на GC для этого. статья Рэймонда Чена об этом является хорошей отправной точкой. По сути, если вы не вручную Close / Dispose вашего соединения, то нет никакой гарантии, что это произойдет, потому что в противном случае это произойдет, только когда Dispose был вызван из Finalizer, что может не произойти. когда-либо случится:

Правильно написанная программа не может Предположим, что финализаторы когда-либо будут работать в любой момент до программы завершение.

Да, на практике финализатор для вашего соединения, вероятно, в конечном итоге произойдет, но даже тогда вы удерживаете действующее соединение дольше, чем вам действительно нужно. Это может создать проблемы, если база данных допускает только ограниченное количество активных соединений одновременно.

То, что вы делаете, считается хорошей практикой: когда вы закончите с ресурсами, освободите их. Если объект IDisposable, Dispose его, когда можете.

6 голосов
/ 23 августа 2010

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

SqlConnection cn = null;
try
{
    cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString());
    cn.Open();

    // Set all previous settings to inactive
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn))
    {
        cmd.ExecuteNonQuery();
    }
    cn.Close();
}
finally
{
    if ( cn != null )
        cn.Dispose();
}

Поскольку cn.Dispose() и cn.Close() в этом случае одинаковы - да, последний является избыточным.

Теперь, если выЕсли вы хотите поговорить о GC, то напишите так:

    SqlCOnnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString());
    cn.Open();

    // Set all previous settings to inactive
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn))
    {
        cmd.ExecuteNonQuery();
    }
    cn = null; // Or just leave scope without doing anything else with cn.

В этом случае потребуется GC, чтобы закрыть открытое соединение и вернуть его в пул.И в этом случае это будет означать, что вы не можете предсказать, когда это произошло.На практике этот код (с высокой вероятностью) будет пропускать SqlConnections, и вскоре вы их исчерпаете (вы получите TimeoutException, поскольку в пуле не будет доступных подключений).

Так что да,Ваш приведенный выше пример - правильный путь.Всякий раз, когда вы используете какой-либо объект, который реализует IDisposable, оберните его в блок using.И вам не нужно беспокоиться о .Close(), хотя это тоже не повредит.Я лично не пишу это все же.Меньше кода, меньше беспорядка.

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