usando la statement FileStream y / o StreamReader – Visual Studio 2012 Warnings

El nuevo Visual Studio 2012 se queja de una combinación de código común que siempre he usado. Sé que parece excesivo pero he hecho lo siguiente en mi código ‘solo para estar seguro’.

using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (var sr = new StreamReader(fs)) { // Code here } } 

Visual Studio me está ‘advirtiendo’ que me estoy deshaciendo de fs más de una vez. Entonces mi pregunta es esta, ¿la forma correcta de escribir esto sería?

 using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var sr = new StreamReader(fs); // do stuff here } 

O debería hacerlo de esta manera (o alguna otra variante no mencionada).

 var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using (var sr = new StreamReader(fs)) { // Code here } 

Busqué varias preguntas en StackOverflow pero no encontré algo que abordara las mejores prácticas para esta combinación directamente.

¡Gracias!

La siguiente es la forma en que Microsoft recomienda hacerlo. Es largo y voluminoso, pero seguro:

 FileStream fs = null; try { fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using (TextReader tr= new StreamReader(fs)) { fs = null; // Code here } } finally { if (fs != null) fs.Dispose(); } 

Este método siempre asegurará que todo lo que se disponga debe ser a pesar de las excepciones que puedan arrojarse. Por ejemplo, si el constructor de StreamReader arroja una excepción, FileStream aún se eliminaría correctamente.

Visual Studio me está ‘advirtiendo’ que me estoy deshaciendo de fs más de una vez.

Lo estás, pero eso está bien. La documentación para IDisposable.Dispose lee:

Si el método Dispose de un objeto se llama más de una vez, el objeto debe ignorar todas las llamadas después de la primera. El objeto no debe lanzar una excepción si su método Dispose se llama varias veces.

Basado en eso, la advertencia es falsa, y mi elección sería dejar el código tal como está, y suprimir la advertencia.

Como la respuesta de Dan solo parece funcionar con StreamWriter, creo que esta podría ser la respuesta más aceptable. (La respuesta de Dan aún dará dos veces la advertencia eliminada con StreamReader – como Daniel Hilgarth y exacerbate las menciones de los expertos, StreamReader elimina la cadena de archivos)

 using (TextReader tr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) { string line; while ((line = tr.ReadLine()) != null) { // Do work here } } 

Esto es muy similar a la respuesta de Daniel Hilgarth, modificada para llamar a disposición a través de la instrucción Using en StreamReader, ya que ahora está claro que StreamReader invocará a disponer en FileStream (De acuerdo con todas las demás publicaciones, se hace referencia a la documentación)

Actualizar:

Encontré esta publicación. Por lo que vale la pena. ¿La eliminación de streamreader cierra la secuencia?

Sí, la forma correcta sería usar tu primera alternativa:

 using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { TextReader tr = new StreamReader(fs); // do stuff here } 

La razón es la siguiente:
Al deshacerse de StreamReader solo se elimina FileStream por lo que en realidad es lo único que necesita deshacerse.

Su segunda opción (solo el “uso” interno) no es una solución, ya que dejaría el FileStream oposición si hubiera una excepción dentro del constructor del StreamReader .

Es porque la forma en que StreamReader elimina la transmisión cuando se desecha. Por lo tanto, si también dispone de la transmisión, la eliminan dos veces. Algunos consideran que esto es un defecto en StreamReader pero no deja de ser importante. En VS 2012 (.NET 4.5) hay una opción en StreamReader para no deshacerse de la secuencia, con un nuevo constructor: http://msdn.microsoft.com/en-us/library/gg712952

Dos soluciones:

A ) Confía en Reflector o Documentación y sabe *Reader y *Writer cerrará *Stream subyacente. Pero advertencia: no funcionará en caso de una excepción lanzada. Por lo tanto, no es la forma recomendada:

 using (TextReader tr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) { // Code here } 

B ) Ignora la advertencia ya que la documentación indica que The object must not throw an exception if its Dispose method is called multiple times. Es la forma recomendada, ya que es una buena práctica usar siempre el uso y seguro en caso de una excepción lanzada:

 [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] internal void myMethod() { [...] using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (TextReader tr = new StreamReader(fs)) { // Code here } } 

Teniendo en cuenta todas las tonterías que esta pregunta (perfectamente legítima!) Generó, esta sería mi preferencia:

 FileStream fs = null; TextReader tr= null; try { fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); tr= new StreamReader(fs); // Code here } finally { if (tr != null) tr.Dispose(); if (fs != null) fs.Dispose(); } 

Los enlaces a continuación ilustran la syntax perfectamente legal. IMO, esta syntax “usar” es mucho mejor que anidar “usar”. Pero lo admito, no resuelve la pregunta original:

EN MI HUMILDE OPINIÓN…