.NET - замена вложенных операторов using одним оператором using - PullRequest
6 голосов
/ 20 октября 2010

Если вы сталкивались с каким-нибудь кодом C #, подобным этому, вложенным с использованием операторов / ресурсов:

using (var response = (HttpWebResponse)request.GetResponse())
{
    using (var responseStream = response.GetResponseStream())
    {
        using (var reader = new BinaryReader(responseStream))
        {
            // do something with reader
        }
    }
}

Безопасно ли заменить его чем-то вроде этого?

using (var reader = new BinaryReader(((HttpWebResponse)request.GetResponse()).GetResponseStream()))
{
    // do something with reader
}

Приведенный выше пример является лишь примером вложенных одноразовых ресурсов, так что извините, если это не совсем правильное использование. Мне любопытно, когда вы располагаете самым внешним ресурсом (в данном случае BinaryReader), будет ли он рекурсивно располагать свои дочерние элементы для вас, или вам нужно явно располагать каждый «слой» с помощью отдельных операторов using? Например. если вы располагаете BinaryReader, должен ли он располагать потоком ответа, который, в свою очередь, удаляет ответ? Размышление об этом последнем предложении заставляет меня думать, что вам действительно нужны отдельные операторы using, потому что нет способа гарантировать, что объект-оболочка избавится от внутреннего объекта. Это верно?

Ответы [ 5 ]

13 голосов
/ 20 октября 2010

Вы должны просто составить ваши операторы использования - это даст желаемый эффект, который вы ищете:

using (var response = (HttpWebResponse)request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var reader = new BinaryReader(responseStream))
{
    // do something with reader
}
12 голосов
/ 20 октября 2010

Вам нужны отдельные операторы using.

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

Чтобы понять почему,посмотрите, что на самом деле делает оператор using .Он берет ваш второй код и делает что-то эквивалентное:

{
    var reader = new BinaryReader(((HttpWebResponse)request.GetResponse()).GetResponseStream());
    try
    {
      // do something with reader
    }
    finally
    {
        if (reader != null)
            ((IDisposable)reader).Dispose();
    }
}

Как вы можете видеть, никогда не будет звонка Dispose() на Response или ResponseStream.

3 голосов
/ 20 октября 2010

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

using (var response = (HttpWebResponse)request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var reader = new BinaryReader(responseStream))
{
    // do something with reader
}

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

2 голосов
/ 20 октября 2010

Согласно документации, BinaryReader.Close закроет основной поток. http://msdn.microsoft.com/en-us/library/system.io.binaryreader.close.aspx

Кроме того, согласно документации для HttpWebResponse, вы должны либо закрыть базовый поток, либо утилизировать ответ. http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx

Итак, второй пример, который вы предоставили, сработает.

0 голосов
/ 21 февраля 2014

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

using (IType1 a = new Type1(), b = new Type1()){}

Это, однако, означает, что выобъекты должны быть одного типа.Вы можете назвать их как

using (IDisposable a = new Type1(), b = new Type2()){}

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

using (var a = new Type1(), b = new Type2()){}

. По-видимому, это дает вам правильно типизированные ссылки на объекты, позволяющие вам получить доступ к правильному методу выделенного типа, и избавляется от обоих объектов.создано.Если кто-то знает, почему я не прав, пожалуйста, дайте мне знать, потому что это работает для меня?(Я знаю, что этот вопрос очень старый, но это все, что я мог найти, когда искал этот ответ сам)

...