Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why disposed object doesn't throw exception on using it after disposing?

Is it legal to call a method on disposed object? If yes, why?

In the following demo program, I've a disposable class A (which implements IDisposable interface).As far as I know, if I pass disposable object to using() construct, then Dispose() method gets called automatically at the closing bracket:

A a = new A();
using (a)
{
   //...
}//<--------- a.Dispose() gets called here!

//here the object is supposed to be disposed, 
//and shouldn't be used, as far as I understand.

If that is correct, then please explain the output of this program:

public class A : IDisposable
{
   int i = 100;
   public void Dispose()
   {
      Console.WriteLine("Dispose() called");
   }
   public void f()
   {
      Console.WriteLine("{0}", i); i  *= 2;
   }
}

public class Test
{
        public static void Main()
        {
                A a = new A();
                Console.WriteLine("Before using()");
                a.f();
                using ( a) 
                {
                    Console.WriteLine("Inside using()");
                    a.f();
                }
                Console.WriteLine("After using()");
                a.f();
        }
}

Output (ideone):

Before using()
100
Inside using()
200
Dispose() called
After using()
400

How can I call f() on the disposed object a? Is this allowed? If yes, then why? If no, then why the above program doesn't give exception at runtime?


I know that the popular construct of using using is this:

using (A a = new A())
{
   //working with a
}

But I'm just experimenting, that is why I wrote it differently.

like image 301
Nawaz Avatar asked Sep 17 '11 18:09

Nawaz


People also ask

Does using dispose on exception?

Dispose() does not get called in the attached code. Further more the exception that is thrown is not handled and the program blows up.

What does Cannot access a disposed object mean?

: 'Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application.

Does Dispose get called automatically?

Dispose() will not be called automatically. If there is a finalizer it will be called automatically. Implementing IDisposable provides a way for users of your class to release resources early, instead of waiting for the garbage collector.

What does dispose method do with?

The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.


2 Answers

Disposed doesn't mean gone. Disposed only means that any unmanaged resource (like a file, connection of any kind, ...) has been released. While this usually means that the object doesn't provide any useful functionality, there might still be methods that don't depend on that unmanaged resource and still work as usual.

The Disposing mechanism exist as .net (and inheritly, C#.net) is a garbage-collected environment, meaning you aren't responsable for memory management. However, the garbage collector can't decide if an unmanaged resource has been finished using, thus you need to do this yourself.

If you want methods to throw an exception after the object has been diposed, you'll need a boolean to capture the dispose status, and once the object is disposed, you throw the exception:

public class A : IDisposable
{
   int i = 100;
   bool disposed = false;
   public void Dispose()
   {
      disposed = true;
      Console.WriteLine("Dispose() called");
   }
   public void f()
   {
      if(disposed)
        throw new ObjectDisposedException();

      Console.WriteLine("{0}", i); i  *= 2;
   }
}
like image 65
Femaref Avatar answered Sep 19 '22 14:09

Femaref


The exception is not thrown because you have not designed the methods to throw ObjectDisposedException after Dispose has been called.

The clr does not automagically know that it should throw ObjectDisposedException once Dispose is called. It's your responsibility to throw an exception if Dispose has released any resources needed for successful execution of your methods.

like image 40
Giorgi Avatar answered Sep 21 '22 14:09

Giorgi