SuppressFinalize in Dispose confusion

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I'm confused about using SuppressFinalize in Dispose.

My class has a Socket member, so FxCop complained that my class needs to
implement IDispose.

Documentation says that either Dispose or the finalizer (destructor?) get
called, but never both. Is that because the examples have SuppressFinalize
being called in Dispose?

In my attempt to follow the examples, I've got a destructor that calls
Dispose(false), a Dispose() that calls Dispose(true) and
GC.SupressFinalize(this), and a Dispose(bool) that looks like:

protected virtual void Dispose( Boolean disposing)
{
if (! disposed)
{
if (disposing)
{
if (listenerSocket != null)
{
listenerSocket.Close();
listenerSocket = null;
}
}
disposed = true;
}
}

First of all, is this right?

Next, I'm confused about SuppressFinalize being called in Dispose(). My
class has other object members. Does my Dispose(bool) need to set them all
to null in order for them to get cleaned up by garbage collection? If not,
when are they available for collection?

I'm also confused about the examples. In the SuppressFinalize documentation
(ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref2/html/M_System_GC_SuppressFinalize_1_b4c5a2da.htm),
for example, in the Dispose(bool disposing) function, it says to dispose of
managed resources only if disposing is true, but to dispose of unmanaged
resource regardless of the value of disposing. Socket is managed, but isn't
it IDisposable because it manipulates an unmanaged resource? So should I
call Socket's Close only if disposing is true, or regardless? By the way,
I'm supposed to call Close, right? I thought I was supposed to call Socket's
Dispose, but that's protected.

Thanks.
 
I also see that FxCop says:

If the type does not own any unmanaged resources, do not implement a
finalizer on it.

This goes to my question about Socket. It's a managed type, but isn't the
reason it's IDisposable because it contains an unmanaged type? So, should my
class that contains a Socket member have a destructor (that calls
Dispose(false)) or not?

Thanks
 
Inline.
I'm confused about using SuppressFinalize in Dispose.

My class has a Socket member, so FxCop complained that my class needs to
implement IDispose.

Documentation says that either Dispose or the finalizer (destructor?) get
called, but never both. Is that because the examples have SuppressFinalize
being called in Dispose?

In my attempt to follow the examples, I've got a destructor that calls
Dispose(false), a Dispose() that calls Dispose(true) and
GC.SupressFinalize(this), and a Dispose(bool) that looks like:

protected virtual void Dispose( Boolean disposing)
{
if (! disposed)
{
if (disposing)
{
if (listenerSocket != null)
{
listenerSocket.Close();
listenerSocket = null;
}
}
disposed = true;
}
}

First of all, is this right?

Yes. It looks fine to me. You probably don't need to set
listenerSocket = null in this particular case, but it's not a big deal.
Next, I'm confused about SuppressFinalize being called in Dispose(). My
class has other object members. Does my Dispose(bool) need to set them all
to null in order for them to get cleaned up by garbage collection?

Well, techically yes. But I think you're thinking about this the wrong
way. In most use cases an object is no longer referenced after its
Dispose method has been called. If it's no longer referenced then it,
along with its associated object graph, are all eligible for
collection. That's why setting listenerSocket = null is usually not
needed.
If not, when are they available for collection?

They are available for collection whenever the GC cannot find a
reference to them. Now, if you continue to hold a reference to your
class after calling Dispose then the other objects referenced inside
your class will not be eligible for collection either. However, the
Socket will be eligible since you explicitly set its reference to null
inside the Dispose(bool) method.
I'm also confused about the examples. In the SuppressFinalize documentation
(ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref2/html/M_System_GC_SuppressFinalize_1_b4c5a2da.htm),
for example, in the Dispose(bool disposing) function, it says to dispose of
managed resources only if disposing is true, but to dispose of unmanaged
resource regardless of the value of disposing. Socket is managed, but isn't
it IDisposable because it manipulates an unmanaged resource?

Yes. It is a managed object that holds unmanaged resources. Since it
is a managed object only call it's Dispose (Close) method when
disposing is true. It doesn't appear that your class holds unmanaged
resources *directly* so there's nothing else you need to do.
So should I
call Socket's Close only if disposing is true, or regardless?

Call Socket.Close or Socket.Dispose only if disposing is true. If
disposing is false then the GC called the Dispose(bool) method and that
means managed object references may not be valid. In other words, the
GC may have already called the Socket's Finalize method because the
order in which the GC calls Finalize is unpredictable.
By the way,
I'm supposed to call Close, right? I thought I was supposed to call Socket's
Dispose, but that's protected.

Calling Close is usually fine. The Dispose method is public. You're
just not seeing it because it's implemented explicitly. You call it by
casting it into an IDisposable reference.
 
uncaged said:
I also see that FxCop says:

If the type does not own any unmanaged resources, do not implement a
finalizer on it.

This goes to my question about Socket. It's a managed type, but isn't the
reason it's IDisposable because it contains an unmanaged type? So, should my
class that contains a Socket member have a destructor (that calls
Dispose(false)) or not?

Nope. Unless you hold onto the resources *directly*, you don't need to
have a finalizer. Instead, Socket (or whatever it uses to hold onto the
handle) should have the finalizer.
 
Thanks, that was very helpful.

Brian Gideon said:
Inline.


Yes. It looks fine to me. You probably don't need to set
listenerSocket = null in this particular case, but it's not a big deal.


Well, techically yes. But I think you're thinking about this the wrong
way. In most use cases an object is no longer referenced after its
Dispose method has been called. If it's no longer referenced then it,
along with its associated object graph, are all eligible for
collection. That's why setting listenerSocket = null is usually not
needed.


They are available for collection whenever the GC cannot find a
reference to them. Now, if you continue to hold a reference to your
class after calling Dispose then the other objects referenced inside
your class will not be eligible for collection either. However, the
Socket will be eligible since you explicitly set its reference to null
inside the Dispose(bool) method.


Yes. It is a managed object that holds unmanaged resources. Since it
is a managed object only call it's Dispose (Close) method when
disposing is true. It doesn't appear that your class holds unmanaged
resources *directly* so there's nothing else you need to do.


Call Socket.Close or Socket.Dispose only if disposing is true. If
disposing is false then the GC called the Dispose(bool) method and that
means managed object references may not be valid. In other words, the
GC may have already called the Socket's Finalize method because the
order in which the GC calls Finalize is unpredictable.


Calling Close is usually fine. The Dispose method is public. You're
just not seeing it because it's implemented explicitly. You call it by
casting it into an IDisposable reference.
 
Thanks !

Jon Skeet said:
Nope. Unless you hold onto the resources *directly*, you don't need to
have a finalizer. Instead, Socket (or whatever it uses to hold onto the
handle) should have the finalizer.
 
To clarify one point:

1. You need to implement IDisposable because the only thing that will call
Dispose() on your socket is your class. If you dont implement it or nobody
calls it then the socket will not be closed until the GC runs its finalizer
which is usually later than you would want.

2. You don't need to implement a finalizer because the GC will call the
finalizer of the socket when it collects it.
In fact even if you had a finalizer it should not touch the socket because
the GC can collect and finalize the socket BEFORE finalizing the object that
references it.

3. You suppress finalization after disposing as an optimization because
there is an associated overhead (it keeps the object around longer than
necessary)
 
2. You don't need to implement a finalizer because the GC will call the
finalizer of the socket when it collects it.
In fact even if you had a finalizer it should not touch the socket because
the GC can collect and finalize the socket BEFORE finalizing the object that
references it.

Not quite - it can finalize the socket, but it can't collect it. If the
referring object resurrects itself (eg assigning a reference to "this"
to a static field somewhere) then the socket object would have to be
kept alive too. It may well have been finalized before this, however,
in which case I wouldn't expect it to behave terribly nicely...
 
Back
Top