.NET - Замена вложенных операторов с помощью одного оператора using

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

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), если он рекурсивно распорядится своими дочерними элементами для вас или вам нужно явно распоряжаться каждым "слоем" отдельными операциями использования? Например. если вы распоряжаетесь BinaryReader, должен ли он использовать поток ответов, который, в свою очередь, распределяет ответ? Думая об этом последнем предложении, я думаю, что вам действительно нужны отдельные операторы using, потому что нет способа гарантировать, что объект-оболочка будет удалять внутренний объект. Правильно ли это?

Ответ 1

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

Согласно документации, 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

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

Ответ 5

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

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()){}

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