Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Object can be disposed of more than once" error

Tags:

c#

dispose

When I run code analysis on the following chunk of code I get this message:

Object 'stream' can be disposed more than once in method 'upload.Page_Load(object, EventArgs)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.

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

I don't understand why it might be called twice, and how to fix it to eliminate the error. Any help?

like image 382
Mike Jones Avatar asked Oct 20 '10 22:10

Mike Jones


2 Answers

I struggled with this problem and found the example here to be very helpful. I'll post the code for a quick view:

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

Replace the outer using statement with a try/finally making sure to BOTH null the stream after using it in StreamWriter AND check to make sure it is not null in the finally before disposing.

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

Doing this cleared up my errors.

like image 98
mxgg250 Avatar answered Sep 28 '22 18:09

mxgg250


To illustrate, let's edit your code

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 

To avoid this, just create the writer directly

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: to take into account what Eric Lippert is saying, there could indeed be a moment when the stream is only released by the finalizer if BinaryWriter throws an exception. According to the BinaryWriter code, that could occur in three cases

  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 
  • if you didn't specify an output, ie if stream is null. That shouldn't be a problem since a null stream means no resources to dispose of :)
  • if you didn't specify an encoding. since we don't use the constructor form where the encoding is specified, there should be no problem here either (i didn't look into the encoding contructor too much, but an invalid codepage can throw)
    • if you don't pass a writable stream. That should be caught quite quickly during development...

Anyway, good point, hence the edit :)

like image 22
samy Avatar answered Sep 28 '22 17:09

samy