Posts Tagged ‘ WeakReference ’

Comparable WeakReferences in C#

C# provides us with a WeakReference object.  This object behaves like a normal reference, except that it does not prevent garbage collection of the target instance it refers to.  So if every other strong reference to an instance goes away or is nulled out, the .NET garbage collector will collect that instance, without regard to the weak references.  WeakReferences also provide an IsAlive property so you can check if the target still exists.

The WeakReference class has a weakness in certain situations that I’d like to address.  Let me start with an example.

Suppose you have two weak references and you want to know if they point to the same instance.  Something like this (very naive) example:

object instance1 = new object();

WeakReference ref1 = new WeakReference(instance1);
WeakReference ref2 = new WeakReference(instance1);

if (ref1 == ref2)
{
    // Do something
}

This will actually fail every time.  It’s comparing the references to the WeakReferences.  Because ref1 is a reference to a WeakReference instance, as is ref2.  What we really want is to compare the targets.  (Usually.)

So here I present the EquatableWeakReference class.  It behaves just like a WeakReference, but if you compare two of them, it compares the targets.

public class EquatableWeakReference
    {
        #region Private Members

        private int _targetHashCode;
        private WeakReference _weakReferenceToTarget;

        private void setTarget(object target)
        {
            _targetHashCode = target.GetHashCode();
            _weakReferenceToTarget = new WeakReference(target);
        }

        #endregion

        #region Public Interface

        public EquatableWeakReference(object target)
        {
            setTarget(target);
        }

        public object Target
        {
            get { return _weakReferenceToTarget.Target; }
            set
            {
                setTarget(value);
            }
        }

        public bool IsAlive
        {
            get
            {
                return _weakReferenceToTarget.IsAlive;
            }
        }

        public override int GetHashCode()
        {
            return _targetHashCode;
        }

        public override bool Equals(object obj)
        {
            return _targetHashCode == obj.GetHashCode();
        }

        #endregion
    }

As you can see, it has a similar constructor, and the same properties as the WeakReference.  It wraps the WeakReference, rather than inheriting from it, because we originally wrote this for use in Silverlight and you can’t inherit from WeakReference in Silverlight.

When you set the target, it records the target’s HashCode.  This is a unique* identifier of that object instance.  It uses those HashCodes to do comparisons.  It also overrides GetHashCode to return the target’s HashCode, rather than the EquatableWeakReference’s HashCode.  This also provides the advantage that if you use an EquatableWeakReference as a key in a Dictionary, it will be treated as the same key as a real reference to that object, because Dictionaries use the HashCode to index values.

(Which brings us to the whole reason for creating this.  We needed to make a WeakDictionary.  A Dictionary that would allow values to be garbage collected if the key instance was no longer alive.  This was a single-point fix to a widespread memory leak in an open-source library we were working with.  Oh, memory leaks… How you amuse me…)

 

* – It’s not really 100% unique, but it was good enough for our purposes.

%d bloggers like this: