1

I have a class with IDisposable interface. Now I don't know what behavior should I implement. Should be thrown an ObjectDisposedException for each method call in this class after Dispose method, or it should only throw exception in specified methods like data access to disposed resources?

I tested Bitmap object (just example):

Bitmap b = new Bitmap (100, 100);
b.Dispose (); // if i remove this line - console will display: Format32bppArgb
Console.WriteLine (b.PixelFormat);
Console.ReadKey ();

And console displays: DontCare

So no exception has been thrown. Bitmap object allow to use PixelFormat property after I called Dispose. Should I follow this behavior?

apocalypse
  • 5,764
  • 9
  • 47
  • 95
  • I just came across this issue also, trying to hunt down a bug. The `Bitmap` object itself is NOT null, but attempting to reference it's properties such as `Width` or `Height` will throw an `ArgumentException`. The only valid property left is `PixelFormat`, which as you mentioned is "DontCare". I don't see where I am not setting the object to null after `Dispose()`ing of it. Very strange. I've even tried to force a GC.Collect() without success in this issue. – Patrick May 04 '16 at 07:55

3 Answers3

1

My philosophy on this and many other issues is "do what makes sense".

In some cases, it may be very reasonable for certain class members to be used after a class has released its resources. Indeed, some scenarios may require such use. For example, if an object manages asynchronous transactions over a network connection, one might ask it to shut down and then, after it has done so, ask it how many transactions had been processed, whether any had been left dangling, etc. The final values of such statistics could not be known until after shutdown is complete, and there is conceptually nothing wrong with asking an object to shut down and then asking it for historical information relating to things it has already done.

While one might argue that Close should shut down the connection while allowing the use of properties that report historical informaion, while Dispose should shut things down and disallow the use of such properties, I regard such a distinction as unhelpful. Among other things, one may wish for the connection to release all resources associated with it (something Close might refrain from doing, in the interest of allowing a "reopen" request). Further, in cases where there's no other difference in behavior between Close and Dispose, I don't see any need to require two separate methods purely so Dispose can invalidate the statistical data.

In some sense, many IDisposable objects may be viewed as having two parts--an entity which is interacts with outside resources, and an entity which interacts with managed code and may have limited functionality by itself. While the "separation of concerns" principle would suggest that the two parts should be separate objects (and indeed, there are tines when such a split can be helpful), in many cases client code is going to want to hold a single reference which can serve both purposes. That reference is going to have to implement IDisposable, but disposal shouldn't destroy the managed-code side of things.

As an example, consider the WinForms Font class. That class encapsulates two things: (1) a collection of information about a font (typeface, size, style, etc.), and (2) a GDI font handle. When a Font is Disposed, it can no longer be used for drawing text, but it does not forget the typeface, style, etc. Given a Disposed font, it is possible to construct a new font using that information from an old one. Unfortunately, most of the properties that would allow such information to be read out are explicitly invalidated by Dispose, which means that in many cases if one wants to produce a font which is similar to an existing-but-disposed Font but has some changes, one must construct a new font with information copied from the old one, construct another new font based upon that one, and then Dispose the first new font that was created. It might have been helpful to have a FontDescription class which held information related to typestyle, etc. so that in cases where one wanted to hold a description of a font but didn't need a GDI handle, the font description could be stored in a non-disposable class, but that's not how the classes were designed.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • I have class `DataBlock (long pSize, int pAlign = 16)`. I have properties like this: Alignment { get; }, Size { get; }, method like: EnterReadMode(), ExitReadMode() etc. In your opinion should I use exception for calling Aligment {get;} ? If memory id disposed, there is no logical aligment and size. Should I implement IsDisposed property and forget about considering which method should throw Exception? – apocalypse Feb 03 '13 at 05:39
  • @zgnilec: See my edit above. I certainly would not go out of my way to invalidate properties that relate information about your type, though I would certainly add `IsDisposed`. Depending upon the semantics of your type, it may be helpful to have a constructor which can take an instance--disposed or not--and produce a new instance which is similar to it (except that the new instance wouldn't be disposed). – supercat Feb 03 '13 at 18:32
1

should only throw exception in specified methods like data access to disposed resources?

That's automatic, a class that has a finalizer should throw in a case like this. After all, the method is going to access an operating system object that's no longer alive, that is going to produce an error. That better be reported with a clear one like ObjectDisposedException instead of a mystifying one produced by the operating system error code.

The Bitmap example you gave is a very sad one, but not uncommon for the GDI+ classes. They in general have very poor error handling. Let this not be an example.

The key phrase in the previous paragraph was "class that has a finalizer". Your class should not have a finalizer so whether you throw yourself instead of leaving it up to the method in the disposable class you encapsulate is debatable. In general you should avoid it, it tends to clutter your code for little real benefit. But feel free to do so if you wrap a crummy class like Bitmap that returns bad data.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Why not finalizer? I read article, and it says finalizer is somtimes required. I have a class DataBlock which internally uses GlobalHAlloc call. Sometimes it allocates 1GB or more memory. So now I have have a bug in code, and I forget to call Dispose, it may be a very bad to keep this 2GB of data in memory... – apocalypse Feb 03 '13 at 05:54
  • Yes, you need a finalizer. I was talking about the 99.9% of the times that you don't. – Hans Passant Feb 03 '13 at 08:12
0

After calling dispose, setting the object to null is the approach I generally follow. Then, you do not need to create any exception, since null exception will be thrown, and it seems to be the proper way.

When an object is null, it does not really matter whether it is null since it is disposed; or it is null as it is not initialized or it is null as it is explicitly set to null. The consumers should know it is null, not the underlying action of being null.

daryal
  • 14,643
  • 4
  • 38
  • 54
  • But in many different places in code, some object can still link to my object. – apocalypse Feb 02 '13 at 07:07
  • @zgnilec your example is not clear for me, in the question after calling dispose, you have stated that b.PixelFormat has a value; thus b seems not been collected by Garbage Collector? – daryal Feb 02 '13 at 07:12
  • Yes, pixel format return new value -> "DontCare". This code is just an example. Question is: If I define a class with IDisposable interface, should I disallow to use all methods in this class after calling Dispose method. – apocalypse Feb 02 '13 at 07:17