The WeakReference class has the property IsAlive. The problem with it, is that you can only trust it if it returns false.
While a WeakReference points to an object that is either live (reachable), or garbage (unreachable) that has not yet been collected by the GC, the IsAlive property will return true. After an object has been collected, if the WeakReference is short (or if the target object does not have a finalizer) then IsAlive will return false. Unfortunately by the time IsAlive returns, the target may have been collected.
This situation can occur because of the way the GC suspends all managed threads before scanning the heap for garbage and collects it (this is an oversimplified explanation for illustrative purposes). The GC can run at any time between two instructions. For example:
Foo f = new Foo();
WeakReference wr = new WeakReference(f);
// code goes here ...
// Garbage Collection may have occurred here!
Foo f2 = (Foo)wr.Target;
If a collection occurred inside the if block, but before the WriteLine, this code would throw a NullReferenceException, since there are no live strong references to f. The only reliable information IsAlive can give you, is that the object is no longer alive since once it’s dead, it’s dead (even resurrecting the target won’t make IsAlive return true once it thinks the object is dead).
The correct pattern for the above code looks like this:
// code goes here...
Foo f2 = (Foo)wr.Target; // new strong reference
So how is IsAlive useful at all? You could imagine implementing a cache by using a collection of WeakReferences, and using the IsAlive property to determine if an object still exists, and if not, replenish the cache. Just be careful to only make decisions based on IsAlive returning false.