This is a reference, and it counts as a valid reference, but only if it's
being used to access instance data. If an instance method is executing,
there must be a root somewhere that can be traced to the instance via a
reference, and the object won't be collected (and later finalized) while the
method is executing assuming that referenced instance data is being
accessed, which is the whole point of Dispose(). You can break this
guarantee by extracting references into non-instance data, but that's a bad
habit to get into, and it's a fairly narrow edge case that doesn't really
get affected by when you call GC.SupressFinalize(). Given type Z, used by
method X.F() like this:
class Z
{
// ....
public void DoSomething() { ... }
}
class X{
public void F(Z z)
{
z.DoSomething();
// other work not involving z...
}
}
X.F is allowed to report z as an unused reference as soon as z.DoSomething()
is invoked, assuming that there is no further activity with z inside X.F
(X.F is not required to wait until z.DoSomething() completes). As a
practical matter though, the processor (or call stack) will then hold a
reference to the object referenced through z, and those are considered roots
to begin tracing. However, if Z.DoSomething() does not require access to
instance data, then the object could still be collected during
Z.DoSomething(), as the roots have no effect. Inside DoSomething, as soon as
the need for a reference to instance data is removed, then DoSomething() is
free to report no need for the reference. As a practial matter, this is only
an issue when you allow finalization-affected references to be exposed or
extracted independently of the objects that encapsulate them.
The need for GC.KeepAlive occurs because if you extract a field into another
reference, and start using that *new* reference instead of the instance's
field, the instance might no longer have any valid references reported
during a collection. If no finalizer exists, there is no effect. If a
finalizer exists, there can be a race condition between the finalizer
working on the instance-bound reference, and any methods that may be
executing using other reference aliases. So this would be an example of
Z.DoSomething() that requires GC.KeepAlive (assuming Z has a finalizer):
public void DoSomething() {
object obj = _myCriticalResourceThatIsFinalized;
// no longer need *this
SomeStaticClass.SomeStaticMethod(obj);
// need to call GC.KeepAlive here
}
Assuming Z has a finalizer that works on _myCriticalResourceThatIsFinalized,
and if GC.KeepAlive is not called where indicated, then
myCriticalResourceThatIsFinalized could get finalized while
SomeStaticClass.SomeStaticMethod is executing on the obj reference, which is
actually the same object.

Signature
Mickey Williams
Author, "Microsoft Visual C# .NET Core Reference", MS Press
www.servergeek.com
> Are you sure? I was under the impression that 'this' didn't count as a
> reference, hence the need for GC.KeepAlive.
[quoted text clipped - 25 lines]
> > > finalization queue. Is there a reason why GC.SuppressFinalize isn't the
> > > first call in the Dispose method?