这两个Singleton实现之间的区别

时间:2012-02-04 11:38:59

标签: c# design-patterns

我正在学习如何实现一些基本的设计模式。在学习Singleton模式的同时,我注意到网络上有两种常见的实现方式:

// Possibly from: http://www.yoda.arachsys.com/csharp/singleton.html
// I cannot remember exact source, sorry :(

public sealed class Singleton
{
    // Static members are 'eagerly initialized', that is,
    // immediately when class is loaded for the first time.
    // .NET guarantees thread safety for static initialization
    private static readonly Singleton instance = new Singleton();

    // Private constructor prevents instantiation from other classes
    private Singleton() { }

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    public static Singleton() { }

    // Get the instance of the singleton
    public static Singleton getInstance()
    {
            return instance;
    }

}

和:

public class Singleton
{
  // Static, VOLATILE variable to store single instance
  private static volatile Singleton m_instance;

  // Static synchronization root object, for locking
  private static object m_syncRoot = new object();

  // Property to retrieve the only instance of the Singleton
  public static Singleton Instance
   {
      get
      {
          // Check that the instance is null
          if (m_instance == null)
          {
              // Lock the object
              lock (m_syncRoot)
              {
                  // Check to make sure its null
                  if (m_instance == null)
                  {
                      m_instance = new Singleton();
                  }
              }
          }

          // Return the non-null instance of Singleton
          return m_instance;
      }
  }
} 
  1. 在什么情况下你会选择急切地初始化vs lazy initialized?
  2. 第一个例子中的注释是否正确,说初始化是线程安全的? (我知道它说的是,但它是互联网...)

6 个答案:

答案 0 :(得分:3)

我绝对会考虑你的第一次实施......

第二个似乎对我有疑问......如果你需要/想要一个懒惰的实现,你可以使用Lazy<T> - 因为它是框架的一部分,感觉更舒服..

BTW:还有更多方法可以实现Singleton模式...... here is an excellent article

答案 1 :(得分:2)

我不确定,但看起来你从这里得到了这些例子:http://www.yoda.arachsys.com/csharp/singleton.html

如果没有,请仔细阅读。关于这两个版本有几点想法。 如果您个人问我:如果我需要知道单身是否已经初始化,我会选择第二个解决方案。

如果您不必处理多线程,我会使用更简单的方法(参见参考链接中的“错误代码”示例)。

答案 2 :(得分:2)

第一个是安全和懒惰的。

static constructor保证只在第一次访问Instrance之前执行一次。如果存在静态构造函数(即使为空),则保证静态字段初始化直接在静态构造函数之前执行。如果没有静态构造函数,则可以更早地进行字段初始化。


第二个是懒惰的,但我不确定双锁模式是否有效。我怀疑它已经坏了,至少在ECMA内存模型中是这样。


在大多数情况下,我个人都会避免任何Class.Instance单例模式支持IoC单例。

答案 3 :(得分:1)

1)这完全是一种设计选择。在需要时预先启动或初始化。

2)是的,它是线程安全的,因为CLR保证单线程对象初始化。 (静态和实例)

修改

就个人而言,在第一个例子中,我将Instance字段公之于众,并免除了getter。有兴趣知道这是不是一个坏主意?

答案 4 :(得分:1)

这是一个单身人士所以我会选择选项1,除非它是一个并不总是需要的大型物体。但我可能不会为那些通常根本没用过的东西做单身。

答案 5 :(得分:0)

两种实现方式都很好,因此取决于您的需求。

如果性能不是问题,请使用第一个的热切创建的实例。否则,使用第二个,其中仅同步第一个访问。