2010-10-20 20 views
28

Cuando funciono análisis de código en el siguiente trozo de código consigo este mensaje:"objeto se puede disponer de más de una vez" error

Object 'corriente' se pueden disponer más de una vez en el método 'upload.Page_Load (objeto, EventArgs) '. Para evitar generar una excepción System.ObjectDisposedException, no debe llamar a Dispose más de una vez en un objeto.

using(var stream = File.Open(newFilename, FileMode.CreateNew)) 
using(var reader = new BinaryReader(file.InputStream)) 
using(var writer = new BinaryWriter(stream)) 
{ 
    var chunk = new byte[ChunkSize]; 
    Int32 count; 
    while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
    { 
     writer.Write(chunk, 0, count); 
    } 
} 

No entiendo por qué podría llamarse dos veces, y cómo solucionarlo para eliminar el error. ¿Alguna ayuda?

+1

A partir de hoy, VS2017 está lanzando CA2202 sobre cada una de las cláusulas 'using'. Alguien tiene que actuar juntos. – ajeh

Respuesta

6

El BinaryReader/BinaryWriter eliminará la transmisión subyacente cuando esté disponible. No es necesario que lo hagas explícitamente.

Para solucionarlo, puede eliminar el uso de todo el Stream.

5

Su escritor dispondrá su transmisión, siempre.

13

Para ilustrar esto, vamos a editar el código

using(var stream = File.Open(newFilename, FileMode.CreateNew)) 
{ 
    using(var reader = new BinaryReader(file.InputStream)) 
    { 
     using(var writer = new BinaryWriter(stream)) 
     { 
      var chunk = new byte[ChunkSize]; 
      Int32 count; 
      while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
      { 
       writer.Write(chunk, 0, count); 
      } 
     } // here we dispose of writer, which disposes of stream 
    } // here we dispose of reader 
} // here we dispose a stream, which was already disposed of by writer 

Para evitar esto, basta con crear el escritor directamente

using(var reader = new BinaryReader(file.InputStream)) 
    { 
     using(var writer = new BinaryWriter(File.Open(newFilename, FileMode.CreateNew))) 
     { 
      var chunk = new byte[ChunkSize]; 
      Int32 count; 
      while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
      { 
       writer.Write(chunk, 0, count); 
      } 
     } // here we dispose of writer, which disposes of its inner stream 
    } // here we dispose of reader 

edit: tener en cuenta lo que Eric Lippert está diciendo, hay podría ser un momento en el que la secuencia solo sea liberada por el finalizador si BinaryWriter arroja una excepción. De acuerdo con el código BinaryWriter, que pudiera ocurrir en tres casos

If (output Is Nothing) Then 
     Throw New ArgumentNullException("output") 
    End If 
    If (encoding Is Nothing) Then 
     Throw New ArgumentNullException("encoding") 
    End If 
    If Not output.CanWrite Then 
     Throw New ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable")) 
    End If 
  • si no se ha especificado una salida, es decir, si la corriente es nula. Eso no debería ser un problema ya que una secuencia nula significa que no hay recursos para deshacerse de :)
  • si no especificó una codificación. ya que no usamos la forma del constructor donde se especifica la codificación, aquí tampoco debería haber ningún problema (no miré demasiado en el contructor de codificación, pero puede lanzar una página de códigos no válida)
    • if you don ' t pasa una secuencia de escritura. Eso debería ser cogido con bastante rapidez durante el desarrollo ...

De todos modos, buen punto, por lo tanto, la edición :)

+2

Ahora, ¿qué ocurre si el nuevo BinaryWriter se lanza después de abrir la secuencia de salida? ¿Quién cierra la secuencia entonces? Nadie, hasta que se ejecute el finalizador. En la práctica, eso no sucede mucho y en la práctica, incluso si sucede, la peor consecuencia es que el archivo permanece abierto un poco demasiado tiempo. Pero si su lógica * requiere * que todos los recursos se eliminen de manera agresiva, sin importar qué locas excepciones ocurran, entonces este código no es correcto. –

+0

@Eric: sí, de hecho, pero como no hay forma en las clases de verificar que el filestream ya está cerrado, no podemos tomarlo en cuenta fácilmente. Si tuviéramos una propiedad Cerrada() como booleana en la secuencia, podríamos agregar lógica de cierre al filestream para manejar casos especiales donde ocurre una excepción en el constructor del Escritor Binario – samy

+0

Más específicamente, si uso el código anterior, y ejecuto el análisis del código Aparece el mensaje de error que dice: llame a System.IDisposable.Dispose en el objeto 'File.Open (string.Concat (upload.BaseDir, newId, CS $ <> 8__locals3.suffix), FileMode.CreateNew)' antes de todas las referencias a está fuera del alcance. –

5

se requiere explícitamente una aplicación adecuada de botar no importa si se le ha llamado más de una vez en el mismo objeto. Mientras que las llamadas múltiples a Descartar son a veces indicativas de problemas lógicos o de un código que podría escribirse mejor, la única forma en que mejoraría el código original publicado sería convencer a Microsoft de que agregue una opción a BinaryReader y BinaryWriter indicándoles que no eliminen sus pases. in stream (y luego use esa opción). De lo contrario, el código requerido para asegurar que el archivo se cierre incluso si el lector o el escritor arroja su constructor sería lo suficientemente feo que simplemente dejar que el archivo se elimine más de una vez parecería más limpio.

10

Luché con este problema y encontré el ejemplo here que me ayudó mucho.Voy a publicar el código para una vista rápida:

using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate)) 
{ 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     // Use the writer object... 
    } 
} 

Reemplazar la instrucción using exterior con un try/finally asegurándose de AMBOS nula la corriente después de usarlo en StreamWriter y comprobar para asegurarse de que no es nulo en el finalmente antes de deshacerse.

Stream stream = null; 
try 
{ 
    stream = new FileStream("file.txt", FileMode.OpenOrCreate); 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     stream = null; 
     // Use the writer object... 
    } 
} 
finally 
{ 
    if(stream != null) 
     stream.Dispose(); 
} 

Haciendo esto solucionó mis errores.

+0

Y gracias por el enlace de MSDN. – Jedidja

Cuestiones relacionadas