delegateによるSingleton
Life is beautiful: Python Hack : 噛めば噛むほどおいしくなるクロージャの話
こちらの記事を読んでC#でも出来るなぁ、っと実験君。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace SingletonSample { // データをチェックするタイプのSingeton class Singleton { static Dictionary<string, object> data; static readonly object syncObj = new object(); public static IDictionary<string, object> Get() { if (data == null) { lock (syncObj) { if (data == null) { data = new Dictionary<string, object>(); data["Hello"] = "World"; } } } return data; } } // delegateを切り替えるSingleton class LambdaSingleton { private static Func<IDictionary<string, object>> get = FirstGet; private static IDictionary<string, object> FirstGet() { lock (get) { // getで呼ばれるメソッドが切り替え済み if (get != FirstGet) return get(); // 初期化処理 Dictionary<string, object> dict = new Dictionary<string, object>(); dict["Hello"] = "World"; // 初期化が完了したのでgetで呼ばれるメソッドを切り替え get = () => { return dict; }; return get(); } } public static IDictionary<string, object> Get() { // このタイミングでgetに対するlockをしなくて大丈夫? return get(); } } class Program { static void Main(string[] args) { const int LOOP = 100000000; // 最初の1回を呼ぶ var dict = LambdaSingleton.Get(); Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < LOOP; ++i) { dict = LambdaSingleton.Get(); } sw.Stop(); Console.WriteLine("Lambda:{0}, {1} - {2}ms.", "Hello", dict["Hello"], sw.ElapsedMilliseconds); // 最初の1回を呼ぶ dict = Singleton.Get(); sw.Reset(); sw.Start(); for (int i = 0; i < LOOP; ++i) { dict = Singleton.Get(); } sw.Stop(); Console.WriteLine("Normal:{0}, {1} - {2}ms.", "Hello", dict["Hello"], sw.ElapsedMilliseconds); } } } /* 結果 Lambda:Hello, World - 1597ms. Normal:Hello, World - 2650ms. */
ただ、ソースにコメント入れたように、getの書き換えがマルチスレッドで安全なのかどうか自信がありません。(^^;