Implementing a generic WeakReference<T> in C#

Check out the replacement EquatableWeakReference class

A weak reference lets you hold a reference to an object that will not prevent it from being garbage collected. There are a few scenarios where this might be important – such as listening for events, caching, various MVC patterns.

.NET and Java supports weak references with the aptly named WeakReference class. In .NET it exposes a .Target property of type object that weakly points to whatever you like.

Java also sports a generic WeakReference to give you a strongly typed version so it’s somewhat puzzling why .NET doesn’t.

Here is my attempt at a WeakReference for .NET. It works fine in the scenarios I’ve used and performance is close to the non-generic version but a quick glance at the SSCLI code for WeakReference reveals that the standard version is a little more complicated and it’s possible there is a reason for that – most likely due to finalizer issues.

using System;
using System.Runtime.InteropServices;

public class WeakReference<T> : IDisposable {
  private GCHandle handle;
  private bool trackResurrection;

  public WeakReference(T target)
    : this(target, false) {
  }

  public WeakReference(T target, bool trackResurrection) {
    this.trackResurrection = trackResurrection;
    this.Target = target;
  }

  ~WeakReference() {
    Dispose();
  }

  public void Dispose() {
    handle.Free();
    GC.SuppressFinalize(this);
  }

  public virtual bool IsAlive {
    get { return (handle.Target != null); }
  }

  public virtual bool TrackResurrection {
    get { return this.trackResurrection; }
  }

  public virtual T Target {
    get {
      object o = handle.Target;
      if ((o == null) || (!(o is T)))
        return default(T);
      else
        return (T)o;
    }
    set {
      handle = GCHandle.Alloc(value,
        this.trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
    }
  }
}

I’ve allowed Target to be settable against my better judgment to bring it more in like with WeakReference. It’s still not serializable though unlike WeakReference.

[)amien

4 responses

  1. Avatar for Marc Brooks

    Could you have inherited from WeakReference and simply cast Target as appropriate?

    Marc Brooks 12 December 2006
  2. Avatar for Damien Guard

    You can't change the object type of a property in a subclass.

    Damien Guard 15 December 2006
  3. Avatar for Stephen Sabey

    I had a similar need and I used inheritance like this:

    Public Class WeakReference(Of T) Inherits WeakReference Public Shadows Property Target() As T Get Return CType(MyBase.Target, T) End Get Set(ByVal value As T) MyBase.Target = value End Set End Property Public Sub New(ByVal target As T) MyBase.New(target) End Sub Public Sub New(ByVal target As T, ByVal trackResurrection As Boolean) MyBase.New(target, trackResurrection) End Sub Public Sub New(ByVal info As System.Runtime.Serialization.SerializationInfo, _ ByVal context As System.Runtime.Serialization.StreamingContext) MyBase.New(info, context) End Sub End Class

    Stephen Sabey 15 December 2008
  4. Avatar for Charles

    This sounds great, however, this duplicates part of the system library...

    I think that a simple inheritance could be acceptable in most of the cases -> the new target would hide the one in the base class, this works in c# (cast to original weakreference type allows recovering the base property)

    Target property would look like something like that: public new T Target { get{...} set{...} }

    Otherwise, an adapter pattern could be applied...

    Well, there are at least 3 ways to implement generic weak references. They need to be balanced with the needs I think.

    Anyway, thanks for sharing your solution!

    Charles 1 August 2011