Let\'s take Wes Dyer\'s approach to function memoization as the starting point:
public static Func Memoize(this Func f)
{
Thomas's answer does not seem to compile under .NET 4.0 due to the enum parameter to the Lazy constructor. I revised it below. I also added an optional parameter for supplying one's own equality comparer. This is useful if TInput does not implement its own Equals or if TInput is a string and you want to make it case insensitive, for example.
public static Func Memoize(
this Func func, IEqualityComparer comparer = null)
{
var map = comparer == null
? new ConcurrentDictionary>()
: new ConcurrentDictionary>(comparer);
return input =>
{
var lazy = new Lazy(() => func(input), LazyThreadSafetyMode.ExecutionAndPublication);
return map.TryAdd(input, lazy)
? lazy.Value
: map[input].Value;
};
}
I did some basic testing of this method using this as my test:
public void TestMemoize()
{
Func mainFunc = i =>
{
Console.WriteLine("Evaluating " + i);
Thread.Sleep(1000);
return i.ToString();
};
var memoized = mainFunc.Memoize();
Parallel.ForEach(
Enumerable.Range(0, 10),
i => Parallel.ForEach(Enumerable.Range(0, 10), j => Console.WriteLine(memoized(i))));
}
It seems to be working correctly.