2009-08-07 22 views
11

He tener algún código similar al siguiente:Stream.Dispose o 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; 
} 

En caso de que este código tenga readStream.Dispose() y responseStream.Dispose() en lugar de establecer tanto en nulo?

+1

+1 ¡Me alegro de que estés haciendo esta pregunta! La mayoría de los códigos de Google copiados y pegados ignoran esto. – n8wrl

+3

Nota al margen, pero puede no ser relevante. No deberías tener un bloque de 'atrapar' todo. Esa no es una buena práctica. Querrá estar buscando, atrapando y manejando excepciones específicas. De lo contrario, desea que la excepción se propague. Si ya eres consciente de esto, perdóname. –

+0

Gracias por todas las respuestas. Comenzaré a deshacerme :-) Para el registro, corté el manejo de excepciones del ejemplo, por lo que no es tan malo como parece, aunque a partir de los comentarios, creo que se trata de otra cosa que se puede mejorar. Gracias de nuevo todos – Temple

Respuesta

28

Es casi siempre un error al establecer las variables locales a nulo, a menos que desee utilizar realmente ese valor más adelante. No obliga a la recolección de elementos no utilizados anteriormente; si no va a leer más adelante la variable, el recolector de elementos no utilizados puede ignorar la referencia (cuando no esté en modo de depuración).

Sin embargo, casi siempre es correcto cerrar las transmisiones, idealmente en una declaración using por simplicidad.

Es también casi siempre es incorrecto tener un bloque de "captura" al descubierto como ese. ¿Realmente desea manejar cualquier cosa que sale mal, incluidas cosas como OutOfMemoryException?

Me gustaría volver a escribir el código como:

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

Ahora bien, si algo va mal, la excepción se propagará a la persona que llama. Es posible que desee detectar algunas excepciones específicas, pero en general no es una buena idea representar errores utilizando un valor que podría haber sido una respuesta "normal" válida.

Finalmente, ¿de verdad está seguro de que quiere Encoding.Default? Esa es la codificación predeterminada de la máquina local ; normalmente desea la codificación indicada por la propia respuesta.

+4

Hay una ventaja al establecer las variables locales en nulo: alerta a otros desarrolladores que necesitan revisar el código de esta persona con mucho cuidado. –

27

Debe tener using [que llama a Dispose()].

2

No, usted debe llamar a Dispose o Cerrar

1

Sí - usted debe llamar explícitamente a Dispose() en las clases que implementan IDisposable después de haberlos usado - esto asegura que todos sus recursos se limpiaron en el momento oportuno. Envolver la variable en un using() hace lo mismo (que añade envolver código que llama a botar para usted):

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

Sí.

Cuando establece en nulo, solo anula la referencia. No ejecuta ningún código de limpieza que haya escrito el creador de la clase Stream.

Quizá desee considerar la declaración using(){ } que maneja esto para usted en tipos IDisposable.

Ejemplo:

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

Sí. Prácticamente todo lo que implementa un método Dispose() debe tener su método Dispose() llamado. Puede llamar de forma implícita en una con la declaración de 'utilizar':

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

Te falta el nombre de variable – thecoop

+1

Whoops. Fijo. –

9

Sí, Eliminarlos().

Incluso mejor que hacer algo como

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

será reescrito Un bloque using(x) {} (por el compilador)
como try {} finally {x.Dispose();}

Tenga en cuenta que la WebRequest no es IDisposable.

También tenga en cuenta que las siguientes líneas de lograr lo mismo que todo el código:

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

Hay algunas trampas en las bibliotecas de .NET. Stream es uno, y el otro es mucho de la API de imágenes. Estas entidades que usan ciertos recursos del sistema no recolectan basura de los recursos del sistema adjuntos.

Si algo usa la API IDisposable, lo mejor que se puede hacer es envolverla en un bloque de uso, como han señalado anteriormente.

Lea sobre "usar", y téngalo en cuenta cada vez que maneje identificadores de archivos o imágenes.

0

Realmente, la pregunta ha sido respondida, pero quiero dar más detalles sobre una cosa.

Cada vez que un objeto implementa la interfaz IDisposable, debe deshacerse de él de con el método Dispose o (mejor aún) utilizar la instrucción using.

Si alguna vez se enfrenta con esta pregunta en el futuro, solo averigüe qué interfaces implementa. Una vez que vea IDisposable, sepa que debe desecharlo.

2

método más seguro:

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"; 
} 

No hay necesidad de disponer de la corriente response.GetResponseStream() explícitamente porque el StreamReader adjunta dispondrá por usted.

EDIT: Estoy de acuerdo con las otras respuestas: atrapar excepciones como esa es una muy mala práctica. Simplemente lo dejé para propósitos de comparación. :-)

0

Si necesita borrar la secuencia, use null; De lo contrario, use el Dispose(); método si su aplicación ya no requiere el uso de la transmisión.

+0

¿Qué significa "borrar la secuencia" y qué tiene que ver establecer una referencia de variable a nulo? –