65.9K
CodeProject is changing. Read more.
Home

LazyWeakReference

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1 vote)

Dec 10, 2012

CPOL
viewsIcon

11100

A simple class for implementing Lazy Phoenix-like weak reference.

Introduction

This tip presents a small and useful class for having a weak reference that reconstructs itself if needed.

Using the code 

Consider the code below:

BigObject someBigObject = new SomeBigObject();
WeakReference aReference = new WeakReference(someBigObject);
//...
//somewhere else, where someBigObject variable is not accessible any more:
if (aReference.IsAlive == true)
{
 //OK, work with it
}
else
{
 //react
}

For those who have worked with weak references this code is quite familiar. Sometimes the action that should be done about weak reference is known - in my case it's often reinitializing the object back to life. Just consider the following code to see what I got:

[Serializable]
public class LazyWeakReference<T>
     where T : class
{
    WeakReference reference;
    Func<T> constructor = null;
    private int reinitializingCounter = 0;

    public LazyWeakReference(T anObject, Func<T> aConstructor = null)
    {
        reference = new WeakReference(anObject);
        constructor = aConstructor;
    }

    public int Reinitialized { get { return reinitializingCounter; } }

    public T Target
    {
        get
        {
            object target = reference.Target;
            if (target == null)
            {
                if (constructor == null) return null;
                T newObject = constructor();
                reinitializingCounter++;
                reference = new WeakReference(newObject);
                return newObject;
            }
            return (T)target;
        }
    }

}

class Program
{

    public static void Main(string[] args)
    {
        LazyWeakReference<StringBuilder> builder = 
          new LazyWeakReference<StringBuilder>(
          new StringBuilder("A builder"), () => 
          new StringBuilder("Acopy"));
        StringBuilder aTarget = builder.Target;
        aTarget = null;
        GC.Collect();
        Console.WriteLine("Reinitialized {0} times",builder.Reinitialized);
        aTarget = builder.Target;
        aTarget = null;
        GC.Collect();
        Console.WriteLine("Reinitialized {0} times", builder.Reinitialized);
        aTarget = builder.Target;
        aTarget = null;
        GC.Collect();
        Console.WriteLine("Reinitialized {0} times", builder.Reinitialized);
        aTarget = builder.Target;
        aTarget = null;
        Console.WriteLine("Reinitialized {0} times", builder.Reinitialized);
        Console.ReadKey();
    }
}

The output is shown below:

Reinitialized 0 times
Reinitialized 1 times
Reinitialized 2 times
Reinitialized 3 times

Points of Interest 

There is no thread-safety issue in this code. You could add it. This functionality is enough for my needs.

History

  • December 10, 2012 - First published.