静态构造函数用于初始化任何静态数据,或用于执行仅需执行一次的特定操作。在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。
静态构造函数具有以下特点:
-
静态构造函数既没有访问修饰符,也没有参数。
-
在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类。
-
无法直接调用静态构造函数。
-
在程序中,用户无法控制何时执行静态构造函数。
-
静态构造函数的典型用途是:当类使用日志文件时,将使用这种构造函数向日志文件中写入项。
-
静态构造函数在为非托管代码创建包装类时也很有用,此时该构造函数可以调用 LoadLibrary 方法。
-
如果没有编写静态构造函数,而这时类中包含带有初始值设定的静态字段,那么编译器会自动生成默认的静态构造函数。
-
如果类中包含用来开始执行的 Main 方法,则该类的静态构造函数将在调用 Main 方法之前执行。
-
如果类中的静态字段带有初始化,则静态字段的初始化语句将在静态构造函数之前运行。
示例:
在此示例中,类 Bus 有一个静态构造函数和一个静态成员 Drive()。当调用 Drive() 时,将调用静态构造函数来初始化类。
public class Bus |
{ |
// Static constructor: |
static Bus() |
{ |
System.Console.WriteLine("The static constructor invoked."); |
} |
public static void Drive() |
{ |
System.Console.WriteLine("The Drive method invoked."); |
} |
} |
class TestBus |
{ |
static void Main() |
{ |
Bus.Drive(); |
} |
} |
我们再来看另外一个例子:
using System; |
class A |
{ |
public static int X; |
static A() // 步骤1 |
{ |
X = B.Y + 1; //此时B.Y为0 |
Console.WriteLine("static A()"); |
} |
} |
class B |
{ |
public static int Y = A.X + 1; // 步骤0 |
static B() //步骤2 |
{ |
Console.WriteLine("static B()"); |
} |
static void Main() |
{ |
Console.WriteLine("X = {0}, Y = {1}", A.X, B.Y); //步骤3 |
Console.ReadLine(); |
} |
} |
运行的结果是:
static A()
static B()
X=1,Y=2
关键是它的执行顺序。
另外下面的一段话也值得思考:
实际上,CLR保证在类的其它操作之前(不包括静态字段的初始化语句)运行静态构造方法。但是,它只保证启动静态构造方法,实际上不保证它的运行结束。因此,可以人为的制造出一种病态情况,两个类互相具有循环依赖关系。这时,CLR会在不同的线程中运行静态构造方法(发现要跑的相应的静态构造函数的线程已经在跑了,则不再发起新线程),以兑现至少以正确的顺序启动两个静态构造方法的最低保证,不会出现死锁。