An Implementation of Lazy(T) with Invalidation

I am a big fan of using Lazy<T> as my go-to implementation of the Singleton pattern. It works well and the thread safety is easily adjustable . While I won’t go into the details of how to use it, all the information is in the Lazy<T> documentation.

For what I needed, however, Lazy<T> fell a bit short. I essentially needed a cache of something that was expensive to create, and could be invalidated when the source object changed. In my case, I had a list that I needed to run some aggregate queries against. Running those queries is expensive, so I only want to re-run them when the list has changed, and I want to run them on demand (don’t compute until the last second when it is needed). In other words, I needed a really simple cache.

Thinking it to be easy enough to implement, I created one, using a Lazy<T> as the implementation. My class, the LazyCache<T>, behaves as you would expect Lazy<T> to behave, but with an additional method: Invalidate(). Please note that I didn’t test the thread safety of the LazyCache<T> and already see some potential problems, so if that is a requirement please take steps to ensure that it will behave as needed.

LazyCache<T> Usage

Here is some demo code that uses the LazyCache<T>

[Test] public void LazyCache_DemonstrationWithObservableCollection()
{
	var data = new ObservableCollection<string>() { "Hi", "Howru" };
	Func<Dictionary<string, int>> dataAsDic = () => data.ToDictionary(x => x, x => x.Length);
	var lazy = new LazyCache<Dictionary<string, int>>(dataAsDic);
	data.CollectionChanged += (sender, e) => lazy.Invalidate();

	Assert.AreEqual(lazy.Value.Count, 2); // "Hi", "Howru"

	data.Add("Tree");

	Assert.AreEqual(lazy.Value.Count, 3); // "Hi", "Howru", "Tree"

	data.RemoveAt(0); // "Howru", "Tree"
	data.RemoveAt(0); // "Tree"

	Assert.AreEqual(lazy.Value.Count, 1); // "Tree"
}

LazyCache<T> Implementation

And here is my implementation of LazyCache<T>:

public class LazyCache<T>
{
	private readonly Func<Lazy<T>> lazyFactory;
	private Lazy<T> lazy;
	private Lazy<T> Lazy
	{
		get
		{
		if (lazy == null)
		{
		lazy = lazyFactory();
		}
		return lazy;
		}
	}

	public LazyCache()
	{
		lazyFactory = () => new Lazy<T>();
	}

	public LazyCache(bool isThreadSafe)
	{
		lazyFactory = () => new Lazy<T>(isThreadSafe);
	}

	public LazyCache(Func<T> valueFactory)
	{
		lazyFactory = () => new Lazy<T>(valueFactory);
	}

	public LazyCache(LazyThreadSafetyMode mode)
	{
		lazyFactory = () => new Lazy<T>(mode);
	}

	public LazyCache(Func<T> valueFactory, bool isThreadSafe)
	{
		lazyFactory = () => new Lazy<T>(valueFactory, isThreadSafe);
	}

	public LazyCache(Func<T> valueFactory, LazyThreadSafetyMode mode)
	{
		lazyFactory = () => new Lazy<T>(valueFactory, mode);
	}

	public bool IsValueCreated { get { return Lazy.IsValueCreated; } }
	public T Value { get { return Lazy.Value; } }
	public void Invalidate()
	{
		lazy = null;
	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *