Cache functions in C# using memoization

March 02, 2010 ASP.NET C# Snippet

Ever wanted to cache the output from a function depending on the parameters in the call, so - that for instance - a heavy calculation that would always return the same answer for a specific parameter set only was computed once? The answer to this i memoization.

In computing, memoization is an optimization technique used primarily to speed up computer programs by having function calls avoid repeating the calculation of results for previously-processed inputs. Read more about memoization at Wikipedia.

This is not very suitable for functions that depend on updated data etc. You might want to tweak the routine to handle a timeout for a couple of minutes to get the best out of both worlds, if that's your case.

Please note that this only works for parameters passed by value. In C# this is the most common data types (string, int, double etc). More complex objects (like arrays or custom objects) is passed by reference.

Source code (.NET 2.0)

public delegate TReturn Function<TParam, TReturn>(TParam param);

static Function<TParam, TReturn> Memoize<TParam, TReturn>(Function<TParam, TReturn> func) {

Dictionary<TParam, TReturn> cache = new Dictionary<TParam, TReturn>();
return delegate(TParam arg) {

TReturn result = default(TReturn);

if (cache.ContainsKey(arg)) {
result = cache[arg];
}
else {
result = cache[arg] = func(arg);
}
return result;
};
}


Testing the code
Lets create a dummy function just for testing purposes. It takes a name as inparameter and returns a string

public string SayHello(string name) {
return "Hello " + name + "! It's now " + DateTime.Now;
}


Setup and call our new function by these lines:

// Create a memoized version of our function
var SayHelloFunc = Memoize<string, string>(SayHello);

string a = SayHelloFunc("Ted");
string b = SayHelloFunc("John");
string c = SayHelloFunc("Ted");


If you set a break point at the first SayHelloFunc call and slowly steps through you'll notice that a and b will contain the exact same timestamp, regardless of the time between the two calls. This is cause their in parameter is the same and the result therefor cached.

The parameters to the Memoize-function are:
Memoize<in-parameter's datatype, return value's datatype>(function name);

Related posts: