On Tue, 27 May 2008 16:40:51 -0700, Michael D. Ober
<obermd.@.alum. mit.edu.nospam. wrote:
First, at some point every non-memory resource in dotNET is a OS
resource and closing it when done is a good thing to do.
No one's suggested otherwise. Keep in mind, of course, that you are
confusing "close" with "dispose". It's true that many classes offer both,
and in many of those cases, the call to Close() does practically or
exactly the same thing as calling Dispose(). But they are two distinct
operations. It's a mistake to refer to one as if it's synonymous with the
other.
dotNET is very good at reusing resources via pooling but Windows itself
isn't,
..NET doesn't do any pooling, except in very specific, documented
scenarios. Even in the classes that implement pooling, you need to
release the resource being used so that it can be returned to the pool.
In at least one case, this involves calling Close() or Dispose() (in that
particular case, the two are equivalent).
I'm not really sure what point you're trying to make, but if you're saying
that one can rely on resource pooling from .NET as an alternative to
calling Close() or Dispose(), that's a very misleading and incorrect
implication to make.
so using the dispose pattern on just about any class that you use and/or
create is a good idea simply from the perspective of being nice to other
applications on the system.
In many cases, the application that is most critically affected by whether
you Close() or Dispose() a class is your own. It's not just a matter of
"being nice".
Second, most decent servers watch for and handle closed distant end
(client or server) sockets by closing a socket when a processing a zero
byte read. This is part of the Berkeley standard for socket
communications.
You are confusing the question of resource disposal and network API. The
socket comparison is apt for illustrating this, ironically enough. In BSD
terminology: a TCP socket uses shutdown() to initiate a graceful closure.
When you do this, the underlying TCP is eventually closed (including a
zero-byte receive at the other end), but the socket resource still lives
on. Not until you call closesocket() is the actual socket cleaned up, but
assuming a graceful closure, the remote endpoint has already been notified
of the closure of the connection (and may have itself already disposed its
own resources), even without disposal of the local resource.
(In .NET, this corresponds closely to the Socket.Shutdown () and
Socket.Close() methods).
Conversely, even if you reset a connection ungracefully (by calling
closesocket() without shutdown()), there is _nothing_ that guarantees that
the remote endpoint will even detect that correctly, never mind will clean
up its own resources. Resource management at the other end is _entirely_
up to the code running on that end.
It is a serious mistake to say that resource management within one's own
application is done for the sake of code running elsewhere. There are in
fact aspects of a network API (for example) that require considerate
behavior so that the other end can more effectively manage its own
resources, but these aspects are entirely independent of the question of
local resource management. Instead, they are part of the
application-level protocol that defines the interaction of the
applications, and this application-level protocol has nothing to do with
the underlying implementation.
Again, closing the non-memory resource via dispose is a good idea so
that any other systems involved in that resource are notified that they
can close their resources.
It's a good idea, but not for the reason you state.
The real problem on whether or not to use dispose is that the framework
has blurred the lines between managed and unmanaged. For someone who has
never written to the underlying OS, the fact that a lot of the framework
classes contains a Dispose method really doesn't have any meaning
because the non-memory OS resource is "hidden" from them.
If you are relying on whether a class implements IDisposable to tell you
whether it includes unmanaged resources, then yes...I can see your
confusion. But that's because IDisposable doesn't tell you that at all.
It's true that a class that includes unmanaged resources really needs to
implement IDisposable, but it's not necessarily the case that IDisposable
means there are unmanaged resources being used.
What you really should be taking away from the IDisposable issue is that
as a .NET programmer, you really shouldn't be worrying about whether some
other class uses unmanaged resources. If the class implements
IDisposable, you should call Dispose() when you're done with it, period.
Not because it might use unmanaged resources (though it very well might),
but because that's the contract defined by the class's API.
The "unmanaged/managed" question is really just a red herring. It's made
worse by your inaccurate claim that calling Dispose() is an effective and
correct way to manage an inter-process communication API (as in your
networking example).
Yes, if you don't explicitly call obj.Dispose or use the "using" design
pattern the framework will eventually call Dispose and release the
underlying resource, but this isn't necessarily a good way of doing this.
That's certainly true.
I'm sorry if it seems like I'm nitpicking, but IMHO it's very important to
get these details right. People synthesize new ideas from what they
believe they already know, and so even if from a practical sense, your
inaccuracies don't have any direct effect on a particular implementation,
feeding people bogus information can lead them to make unforeseen
erroneous decisions in the future. Anyone who treats IDisposable as part
of a protocol management strategy for inter-process communications is
eventually going to be write some code that doesn't do what they think it
does, introducing one or more bugs that are potentially difficult to find
and fix.
Pete