C# 单例类

有时候我们不要在一个程序中创建太多的实例。只想用一个全局的实例和一个可以访问点。那么我们需要一个单例类。

因为是单例类啦,所以构造函数肯定是私有的。

需要了解的术语

懒汉式

顾名思义。什么时候用就什么时候去new实例。

比如:

class Singleton
{
    private static Singleton instance = null;

    private Singleton()
    {

    }

    public static Singleton Instance
    {
        get
        {
            if(instance == null)
            {
                instance = new Singleton();
            }

            return instance;
        }
    }
}

饿汉式

还没用就已经有实例对象

比如把上面的代码改一改:

class Singleton
{
    private Singleton()
    {

    }

    public static Singleton Instance { get; } = new Singleton();
}

不过同样,这样就不知道到底是时候构造的。

线程不安全/安全

毕竟new一个对象是个动态的过程。步骤还是有点的。如果多个线程访问同一个实例。由于存在共享变量。可能会造成前一个还没好,后面一个有进来的情况。最后有多少线程,就创建多少实例。这样就称为线程不安全。

相反,如果对同一个类不会造成影响。那么就是安全的。

第一个代码片段是不安全的。第二个代码片段是安全的(在线程还没出现之前就已经实例化了,因此饿汉式线程一定是安全的)。

懒汉式 线程安全

因为我们还是怕共享变量的。所以加锁了。

class Singleton
{
    private static Singleton instance;
    private readonly static object lockobj = new object();
    private Singleton()
    {

    }

    public static Singleton Instance
    {
        get
        {
            lock (lockobj)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }

            return instance;
        }
    }
}

但每次都加锁,肯定很慢的啦。于是,打算只有第一次创建的时候加锁。

class Singleton
{
    private static Singleton instance;
    private readonly static object lockobj = new object();
    private Singleton()
    {

    }

    public static Singleton Instance
    {
        get
        {
            if(instance == null)
            {
                lock (lockobj)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }

            return instance;
        }
    }
}

如果还是怕不知道什么时候构建。可以使用内部类。保证一下

public class Singleton
{
    class Nested
    {
        internal static readonly Singleton instance = new Singleton();
    }
    private Singleton() { }
    public static Singleton Instance { get { return Nested.instance; } }
}

实现单例基类

最后一个是看别人的。

public abstract class Singleton<T> where T : class
{
    class Nested
    {
        // 创建模板类实例,参数2设为true表示支持私有构造函数
        internal static readonly T instance = Activator.CreateInstance(typeof(T), true) as T;
    }
    private static T instance = null;
    public static T Instance { get { return Nested.instance; } }
}

class TestSingleton : Singleton<TestSingleton>
{
    // 将构造函数私有化,防止外部通过new创建
    private TestSingleton() { }
}