Попытка лучше понять выражение «использование» - PullRequest
5 голосов
/ 15 ноября 2011

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

Проблема в том, что все примеры всегда показывают что-то вроде этого:

using (SqlCommand scmFetch = new SqlCommand())
{
    // code
}

Это имеет смысл, но это такой маленький кусочек кода. Что я должен делать при выполнении запроса к базе данных? Каковы все шаги? Будет ли это выглядеть примерно так:

string sQuery = @"
    SELECT [ID], [Description]
    FROM [Zones]
    ORDER BY [Description] ";

DataTable dtZones = new DataTable("Zones");

using (SqlConnection scnFetchZones = new SqlConnection())
{
    scnFetchZones.ConnectionString = __sConnectionString;
    scnFetchZones.Open();

    using (SqlCommand scmdFetchZones = new SqlCommand())
    {
        scmdFetchZones.Connection = scnFetchZones;
        scmdFetchZones.CommandText = sQuery;

        using (SqlDataAdapter sdaFetch = new SqlDataAdapter())
        {
            sdaFetch.SelectCommand = scmdFetchZones;
            sdaFetch.Fill(dtZones);
        }
    }

    if (scnFetchZones.State == ConnectionState.Open)
        scnFetchZones.Close();
}

Что я хочу знать:
• Можно ли вкладывать 4, 5, 10 с помощью операторов, чтобы гарантировать удаление всех объектов?
• В какой момент я делаю что-то не так и должен ли я рассмотреть пересмотр?
• Если требуется ревизия из-за слишком большого количества вложенных операторов операторов, каковы мои варианты?

У вас может сложиться внушительная иерархия, но ваш код должен быть достаточно эффективным, верно? Или вы должны поместить, например, только объект SqlDataAdapter в оператор using, и это так или иначе обеспечит удаление всех других объектов?

Thanx.

Ответы [ 8 ]

8 голосов
/ 15 ноября 2011

Вполне допустимо иметь много вложенных операторов using:

using(A a = new A())
using(B b = new B())
{
   a.SomeMethod(b);
}
2 голосов
/ 15 ноября 2011

Использование оператора является синтаксическим сахаром C #.

Итак, следующий код:

using(var someDisposableObject = new someDisposableObject())
{
    // Do Something
}

на самом деле выглядит так:

var someDisposableObject = new someDisposableObject();
try
{
  // Do Something
}
finally
{
   if (someDisposableObject != null)
   {
       ((IDisposable) someDisposableObject).Dispose();
   }
}

Посмотрите на эту статью: http://msdn.microsoft.com/en-us/library/yh598w02.aspx

2 голосов
/ 15 ноября 2011

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

1 голос
/ 15 ноября 2011

• Можно ли вкладывать 4, 5, 10 с помощью операторов, чтобы гарантировать удаление всех объектов?

Ответ: Вы не можете ограничить использование вложенных «использующих блоков».

• В какой момент я делаю что-то не так и должен ли я рассмотреть ревизию?

Ответ: Если у вас много вложенных «использующих блоков». Пожалуйста, попробуйте, как показано ниже.

        using (var con = new SqlConnection(connStr))
        using (var cmd = new SqlCommand(queryStry))
        using (var rs = cmd.ExecuteReader())
        {
            while (rs.Read())
            {
                //Code.
            }
        }
1 голос
/ 15 ноября 2011

Нет ограничений по глубине, так что это не проблема. Вы должны убедиться, что объект с использованием реализует IDisposable. И располагаемый объект не располагает всеми объектами, связанными с ним, а только теми, которые он создает.

Итак, в какой момент вы делаете неправильно: нет предела, но, как правило, он довольно неглубокий: вы создаете объект, выполняете задачу, затем объект удаляется. Если вы делаете это очень глубоко, я бы посмотрел на дизайн. Я думаю, вам будет трудно сделать это глубже, чем несколькими слоями.

Что касается ваших вариантов редизайна, это действительно зависит от того, что вы делаете, но вы можете использовать один и тот же объект для нескольких задач. Скорее всего, вы в конечном итоге разбите задачу на функцию (передавая любые необходимые окружающие объекты).

0 голосов
/ 15 ноября 2011

Однажды я могу вспомнить, где вы не захотите хотеть использовать 'использование' для соединений, будет в ClassFactories для связанных объектов, таких как DataReaders, например, рассмотреть случай

private IDataReader CreateReader(string queryString,
    string connectionString)
{
    SqlConnection connection = new SqlConnection(connectionString);
    SqlCommand command = new SqlCommand(queryString, connection);
    connection.Open();
    return command.ExecuteReader(CommandBehavior.CloseConnection);
    // Don't close connection
}

(Модифицировано из MSDN - пример на MSDN просто глуп)

Другая причина на WCF ServiceReference 'клиенты' - если канал становится неисправным,«использование» затем скрывает фактическое исключение.Но это просто ошибочная реализация ИМХО.

0 голосов
/ 15 ноября 2011

ИМХО, вы должны спросить себя: каковы альтернативы?Попробуйте / наконец блоки?Они более читабельны?Более ремонтопригодны?Почти во всех случаях ответом будет «нет».

Поэтому используйте using.Это самое близкое, что есть у C # к шаблону RAII в C ++, и все это хорошо: -)

0 голосов
/ 15 ноября 2011

Лично я использовал как минимум 3 слоя (Соединение, Команда, Другое) несколько раз, и я не вижу абсолютно никаких проблем с ним, но, как вы уже намекали, в конечном итоге возникнет проблема читабельности. Как и в случае других вложенных конструкций, вам может потребоваться сбалансировать эффективность с ремонтопригодностью. То есть вам не нужно обязательно жертвовать эффективностью, но часто существует «несколько способов убить кошку».

Тем не менее, вам будет трудно создать 10 вложенных слоев!

...