首先直接文章作者及回复中的兄弟提到的两种Singleton方法。

第一种



    

public   class  Singleton

    



{

        private static Singleton _instance = null;

        private static readonly object lockHelper = new object();

        private Singleton()

        

{

        }

        public static Singleton CreateInstance()

        

{

            //这样lock以及lock块内的代码只会在第一次调用CreateInstance方法的时候执行,

            //第一次调用该方法后_instance就不再为null了,if块内的代码就无须执行了

            if (_instance == null)

            

{

                lock (lockHelper)

                

{

                    if (_instance == null)

                        _instance = new Singleton();

                }

            }

            return _instance;

        }

    }

第二种



public  

class  Singleton

    

{

        private static readonly Singleton _instance = new Singleton();


        static Singleton() 

{ }


        private Singleton() 

{ }


        public static Singleton CreateInstance() 

{ return _instance; }

    }

先说说以上两种方法。 


第一种方法, 显而易见的, 性能不佳; 而且最好加上一句 Thread.MemoryBarrier()。 这是为了线性化内存存取, 避免处理器调整指令顺序导致问题, 至于到底怎么个坏掉法, 我就糊里糊涂了。 但至少从这个角度看, 其实第一种方法, 虽然我们最常用, 如果不加这么一句, 可能反而是不安全的。


 第二种方法, 有兄弟说它不是线程安全的, 事实上它是线程安全的, 但不一定是AppDomain安全的。 在同一个AppDomain内, 初始化仅进行一次。但是这种方法有一个细节。 对于没有静态构造函数的类, .NET会加上一个 BeforeFieldInit的标志,它的MSDN解释是:Specifies that calling static methods of the type does not force the system to initialize the type.  这就是说, 假设Singleton存在一个静态方法, 比如Singleton.Do(), 这个Do被执行了, 但是_instance并不一定被初始化(当然也不一定不被),只要没有其它条件触发(在后面我们会想一个办法, 保证一定得到这个LazyLoad的效果); 也就是说, 初始化的时间是不固定的; 而且还有别的可能:  比如在程序集被加载, 在该类被某种方式访问, 甚至一个很随机的时刻。 传说中初始化仅仅保证在该字段被访问之前, 由运行时决定, 到底咋回事就不是我关心的范畴了。


其实早晚本来也是无所谓的, 关键是注意到这一点, 可以避免并没有触发初始化, 可是流程上人脑中有一个预期的行为,进行编程时所造成的不确定性(尽管很难想象能够掉进这个陷阱的场景,估计得特别特殊的应用, 比如你脑海里以为初始化了, 就向其它东西发一个信号, 而且会造成问题等等)。


如果存在静态构造函数, 那么当这个类的任意成员被访问前, 会进行初始化。 微软这么设计显然是有道理的: 既然写了静态构造器, 那么编程者很显然希望它最早执行, 同时也就会捎带上初始化。 但这种方式会导致, 如果咱们访问Singleton.Do(), 那么所有的字段都会被初始化。也许我们调用Do()的时候因为用不着这个实例, 而且这个实例会耗费很多资源,于是就想尽量Lazy Load用不着就不new, 这样要么使用第一种方法, 或者引出了第三个方法。



     public  

class  Singleton

    

{

        private Singleton() 

{ }


        public static Singleton CreateInstance() 

{ return Holder._instance; }


        private class Holder

        

{

            static Holder()

            

{

            }


            public static readonly Singleton _instance = new Singleton();

        }

    }

用内部私有的类Holder玩一个花招, 实际上这是一种最好的办法: 当Holder被访问时, new Singleton(), 而Do()的时候, 则不会这么做。这样, 它既有第一种方法LazyLoad的特性, 又具有第二种方法的直接性和性能, 还避免了乱七八糟的很难搞明白的问题。


回头再说说关于第一种方法的另一个替代品, 这样:



public   class  Singleton


{

            public static Singleton _instance = null;


            private Singleton()

            

{


            }


            public static Singleton CreateInstance()

            

{

                Interlocked.CompareExchange<Singleton>(ref _instance, new Singleton(), null);

                return _instance;

            }

}


因为 Interlocked.CompareExchange是一个原子操作, 所以是线程安全的。不过注意那个new Singleton(), 它会不断的被执行。 如果构造的过程很耗费资源, 这是一个问题。 其实利用delegate, 我们可以有一些新玩法, 把包括第二次及以后进入CreateInstance的开销降到最低; 如果谁想到了可以给我留言。(Update: 我的做法放在了第20楼, 注意脑袋回复中提到的问题, 其实这种做法我一般用在别处完成更贴切的任务, 具体分析日后再说了)


最后, 稍加改动, 可以把Singleton成泛型的。不过个人感觉意义不大了, 除非用Singleton的地方太多, 懒得打代码, 也可以考虑。 嗯, 结束了么? 不知道大家觉得这些是不是也一塌糊涂,自己感觉我不太适合写这类文章....