实现单例模式主要有5种方法,分别是定义静态实例(只适用于单线程),两种加锁方式(一种消耗较大,一种过于复杂),以及重点的两种使用静态构造函数的方法。
依赖静态构造函数实现单例01:
public sealed class Singleton1
{
private static Singleton1 instance = new Singlenton1;
public static Singleton1 Instance{get{ return instance; }}
}
其中实例在初始化的时候就已经创建好,保证了只有一个实例。
依赖静态构造函数实现单例 02:
public sealed class Singleton
{
public static Singleton Instance
{ get { return Nested.instance; } }
class Nested
{
internal static Singleton2 instance = new Singleton();
}
}
此为方法01的优化,添加了一个内部类Nested,由于Instance是一个静态属性,只有当其被用到时才会触发get,将Singleton类实例化。
不推荐的其他三种实现方法:
01.通过判断变量instance的状态来创建实例,在多线程无法使用
public sealed class Singleton
{
private static Singleton instance = null;
public static Singleton Instance {
get{
if(instance == null)
instance = new Singleton();
return instance;
}
}
}
02.在01的基础上加锁来保证在多线程上的使用,但频繁加锁会导致效率变低
public sealed class Singleton
{
private static object obj = new object();
private static Singleton instance = null;
public static Singleton Instance
{
get
{
lock (obj)
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
}
}
03.在02的基础上增加了对instance的判断,使加锁的频率下降,但代码过于繁琐
public sealed class Singleton
{
private static object obj = new object();
private static Singleton instance = null;
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (obj)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
由以上可知,实现单例最高效的方法是依赖静态构造函数,关于静态构造函数本人找到一个颇有代表性的面试题:
public class A
{
public static readonly int x;
static A()
{
x = B.y + 1;
}
}
class B
{
public static int y = A.x + 1;
static void Main(string[] args)
{
Console.WriteLine("x:{0},y:{1}。", A.x, y);
Console.ReadLine();
}
}
//x:1 y:2
此题对静态实例的操作顺序进行了考察
C#高效编程里说到,这样一段话:
创建某个类型的第一个实例时,所进行的操作顺序为:
1.静态变量设置为0
2.执行静态变量初始化器
3.执行基类的静态构造函数
4.执行静态构造函数
5.实例变量设置为0
6.执行衯变量初始化器
7.执行基类中合适的实例构造函数
8.执行实例构造函数
详解如下:
1、首先,每一个项目有且只能有一个静态类的main函数作为入口函数。
而入口函数是最最先执行的。
2、由于main函数在B类里面,首先会初始化B类。而类的初始化顺序是:类里的静态变量,然后执行静态构造函数。
3、运行起先执行public static int y = A.x + 1;这个,执行这个的时候,先把y初始化为0.然后计算y的值。
4、计算y的值的时候,调用了A的静态变量x。那么就先初始化A类。
5、初始化A类时首先去执行public static readonly int x;执行这句,先把x初始化为0.
6、执行完接着执行A的静态构造函数x = B.y + 1;这是y还是初始化0.
7、计算得到x=1.然后回到public static int y = A.x + 1;得到y=2
8、然后再执行main函数。得出结果x=1,y=2