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 Dispose
d, it can no longer be used for drawing text, but it does not forget the typeface, style, etc. Given a Dispose
d 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.