Stream.Dispose или stream = null?

У меня есть код, похожий на этот:

HttpWebRequest req;
HttpWebResponse response;
Stream receiveStream = null;
StreamReader readStream = null;
try
{
    req = (HttpWebRequest)WebRequest.Create("someUrl"));
    req.Credentials = CredentialCache.DefaultCredentials;

    req.Method = "GET";

    response = (HttpWebResponse)req.GetResponse();
    receiveStream = response.GetResponseStream();
    readStream = new StreamReader(receiveStream, Encoding.Default);

    return readStream.ReadToEnd();
}
catch
{
    return "Error";
}
finally 
{
    readStream = null;
    receiveStream = null;
    response = null;
    req = null;
}

Если этот код имеет readStream.Dispose() и responseStream.Dispose() вместо того, чтобы оба значения равны нулю?

Ответ 1

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

Однако почти всегда правильно закрывать потоки - в идеале в инструкции using для простоты.

Также почти всегда неправильно иметь открытый блок "catch". Вы действительно хотите справиться с чем-то не так, включая такие вещи, как OutOfMemoryException?

Я бы переписал ваш код как:

HttpWebRequest req = (HttpWebRequest) WebRequest.Create("someUrl"));
req.Credentials = CredentialCache.DefaultCredentials;
req.Method = "GET";

using (WebResponse response = req.GetResponse())
{
    using (StreamReader reader = new StreamReader(response.GetResponseStream(),
                                                  Encoding.Default))
    {
        return reader.ReadToEnd();
    }
}

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

Наконец, вы действительно уверены, что хотите Encoding.Default? Это стандартная кодировка локальной машины - вы обычно хотите кодировку, указанную самим ответом.

Ответ 2

Он должен иметь using [который вызывает Dispose()].

Ответ 3

Да, Dispose() их.

Еще лучше сделать что-то вроде

using (HttpWebResponse response = (HttpWebResponse)req.GetResponse() )
using (Stream receiveStream = response.GetResponseStream() )
using (readStream = new StreamReader(receiveStream, Encoding.Default) )
{
   return readStream.ReadToEnd();
}
Блок

A using(x) {} будет перезаписан (компилятором)
как try {} finally {x.Dispose();}

Обратите внимание, что WebRequest не IDisposable.

Также обратите внимание, что следующие строки выполняют то же самое, что и весь ваш код:

using (var client = new System.Net.WebClient())
{
    client.Encoding = ...;
    client.Credentials = ...;
    return client.DownloadString("SomeUrl");
}

Ответ 4

Да. Практически все, что реализует метод Dispose(), должно иметь вызванный метод Dispose(). Вы можете неявно вызвать его в с помощью инструкции "using":

using(StreamReader stream = GetStream())
{
   stream.DoStuff();
}

Ответ 5

Да.

Когда вы устанавливаете значение null, оно только нулевое значение ссылается. Он не запускает код очистки, созданный создателем класса Stream.

Вы также можете рассмотреть инструкцию using(){ }, которая обрабатывает это для вас по типам IDisposable.

Пример:

using (MyDisposableObject mdo = new MyDisposableObject)
{
   // Do some stuff with mdo
   // mdo will automatically get disposed by the using clause
}

Ответ 6

Нет, вы должны вызвать Dispose или Close

Ответ 7

Самый безопасный метод:

try {
    HttpWebRequest request = (HttpWebRequest) WebRequest.Create("someUrl");
    request.Credentials = CredentialCache.DefaultCredentials;
    request.Method = "GET";
    using (HttpWebResponse response = (HttpWebResponse) request.GetResponse()) {
        using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default)) {
            return reader.ReadToEnd();
        }
    }
} catch {
    return "Error";
}

Нет необходимости выделять поток response.GetResponseStream() явно, потому что прикрепленный StreamReader будет использовать его для вас.

РЕДАКТИРОВАТЬ: Я согласен с другими ответами - ловушки исключений вроде очень плохой практики. Я просто оставил его для сравнения.: -)

Ответ 8

Да. Вы должны явно вызвать Dispose() для классов, которые реализуют IDisposable после того, как вы их использовали, - это гарантирует своевременную очистку всех их ресурсов. Обтекание переменной в using() делает то же самое (что добавляет код упаковки, который вызывает Dispose для вас):

using (StreamReader reader = new StreamReader()) {
    // do stuff with reader
}

Ответ 9

В библиотеках .net есть несколько исправлений. Поток является одним, а другой - частью API обработки изображений. Эти объекты, которые используют определенные системные ресурсы, не мусор собирают подключенные системные ресурсы.

Если что-то использует API IDisposable, лучше всего это обернуть его в блок использования, как указали выше люди.

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

Ответ 10

Действительно, на этот вопрос был дан ответ, но я хочу остановиться на одном.

Каждый раз, когда объект реализует интерфейс IDisposable, вы должны распоряжаться им с помощью метода Dispose или (еще лучше) с помощью оператора using.

Если вы когда-либо сталкиваетесь с этим вопросом в будущем, просто узнайте, какие интерфейсы он реализует. Когда вы увидите IDisposable, вы знаете, что хотите его уничтожить.

Ответ 11

Если вам нужно очистить поток, используйте null; В противном случае используйте Dispose(); если ваше приложение больше не требует использования потока.