This project has moved. For the latest updates, please go here.

[Info] Cache Pattern

Coordinator
Nov 11, 2014 at 5:38 PM
Edited May 14, 2016 at 7:24 PM

This article has been moved to GitHub!


The cache stores computed or external data in a local storage so that subsequent requests can be served faster.

The Lazy<T> class of the .NET Framework can be seen as a simple implementation of the Cache Pattern. It stores the value created by the specified factory when the Value property is requested the first time. All future requests of the Value property are served by returning the stored value.

A cache can be marked as dirty if the stored value is outdated. As a result the next request for the value requires that the data is updated first. The following implementation shows how such a Cache could be implemented:
public class Cache<T>
{
    private readonly Func<T> valueFactory;
    private bool isDirty;
    private T value;
        
    public Cache(Func<T> valueFactory)
    {
        if (valueFactory == null) { throw new ArgumentNullException("valueFactory"); }
        this.valueFactory = valueFactory;
        this.isDirty = true;
    }

    public T Value
    {
        get
        {
            if (isDirty)
            {
                isDirty = false;
                value = valueFactory();
            }
            return value;
        }
    }

    public bool IsDirty { get { return isDirty; } }

    public void SetDirty()
    {
        isDirty = true;
    }
}
The next code snippet shows how the Cache class can be used:
internal class ExampleComponent
{
    private readonly Cache<double> calculatedValue;
    private double inputParameter;

    public ExampleComponent()
    {
        this.calculatedValue = new Cache<double>(TimeExpensiveCalculation);
    }

    public double CalculatedValue { get { return calculatedValue.Value; } }

    public double InputParameter 
    {
        get { return inputParameter; }
        set
        {
            if (inputParameter != value)
            {
                inputParameter = value;
                calculatedValue.SetDirty();
            }
        }
    }

    private double TimeExpensiveCalculation()
    {
        // Simulate an expensive operation
        Thread.Sleep(200);  
        return InputParameter;
    }
}
The ExampleComponent class uses the Cache implementation to improve the performance of multiple read requests of the CalculatedValue property.