C# でクラスのメソッドを無理やりメモ化

以前、C# で関数をメモ化するサンプルを紹介しました。

メモ化って便利。でもこのままだと、関数を使うときに毎回メモ化しなければいけません。ちょっと面倒です。クラスのメソッドをあらかじめメモ化しておき、利用側はメソッドを呼び出すだけにしたい。

そこで、Func とラムダ式を使って、クラス内部でメソッドを無理やりメモ化してみました。

using System;
using System.Collections.Generic;
using System.Threading;

namespace MemoSample
{
    public static class MemoUtil
    {
        // 関数をメモ化します。
        public static Func<T, TResult> Memoization<T, TResult>(Func<T, TResult> method)
        {
            Dictionary<T, TResult> cache = new Dictionary<T, TResult>();
            return x =>
            {
                if (!cache.ContainsKey(x))
                {
                    cache[x] = method(x);
                }
                return cache[x];
            };
        }
    }

    public class Greeting
    {
        // メソッドを格納するフィールドを用意して、
        // そこにメモ化した匿名メソッドをセット。
        public readonly Func<string, string> Greet = MemoUtil.Memoization<string, string>(name =>
        {
            Thread.Sleep(2000);
            return string.Format("Hello, {0}", name);
        });
    }

    class Program
    {
        static void Main(string[] args)
        {
            Greeting g = new Greeting();

            Console.WriteLine(g.Greet("Ichiro"));
            Console.WriteLine(g.Greet("Hideki"));
            Console.WriteLine(g.Greet("Ichiro"));

            Console.ReadLine();
        }
    }
}

厳密には、メモ化しているのは匿名メソッドですけど…。クラスを使う側からすれば、使い勝手はたいして変わらないはず。フィールドの宣言と初期化を同時に行っているので、メソッドの定義に近い記述ができています。