先给出静态构造函数的特点然后依次讲解:
- 静态构造函数没有修饰符(public,private),无参数,无返回类型。
- 静态构造函数前面必须是static关键字。如果不加就是普通的构造函数(注意区分修饰符和关键字的区别)
- 静态构造函数有
.Net
框架自动调用,无需程序员介入。这也变相解释了没有修饰符的原因。 - 一个类有且只能有一个静态构造函数。
- 静态构造函数的调用时机只有两种情况:1)类被实例化时自动调用。2)静态成员被调用的时先调用静态构造函数,并且是由.net框架来调用静态构造函数来初始化静态成员变量。
- 在整个项目生命周期中,静态构造函数只会被执行一次。
- 无参数的静态构造函数和无参数的构造函数是可以并存的。
- 如果类中定义了静态变量但没有定义静态构造函数,框架自动会帮我们生成一个静态构造函数来让框架自身来调用。与构造函数同理。
- 调用顺序:静态变量初始化–》静态构造函数–》成员变量初始化–》普通构造函数。
- 在多线程中静态构造函数是线程安全的。
代码一
class Program
{
static void Main(string[] args)
{
Console.WriteLine(StaticConstructorTest.count); //A
Console.WriteLine(StaticConstructorTest.count); //B
}
}
class StaticConstructorTest
{
public static int count = 0;
static StaticConstructorTest()
{
count++;
}
}
输出
1
1
解析
代码的内容是连续两次调用类StaticConstructorTest中的静态变量count并打印。
首先执行A行代码。此时初始化count为0,然后调用静态构造函数,count=1并打印。
在执行B行时,由于程序在生命周期内已经调用过静态构造函数了,因此不能再继续调用,所以count值不变。
可以继续往下思考,在并发的时候利用该特性。当有两个线程A和B,如果线程A没有被初始化,则进行初始化,初始化成功后进入同步阻塞状态。此时若线程B在并发调用,但会阻寒。当线程A调用完成后,阻塞状态解除,线程B进入,这时会检测到构造函数已经被初始化了,所以直接跳过。
代码二
class Program
{
static void Main(string[] args)
{
Console.WriteLine(SmapleA.staticStr); //A
Console.WriteLine(SmapleB.staticStr); //B
}
}
class SmapleA
{
public static string staticStr;
public string normalStr;
static SmapleA()
{
staticStr = "This is a static string A";
Console.WriteLine("This is static constructor A");
}
public SmapleA()
{
normalStr = "This is a normal string A";
Console.WriteLine("This is normal constructor A");
}
}
class SmapleB : SmapleA
{
static SmapleB()
{
staticStr = "This is a static string B";
Console.WriteLine("This is static constructor B");
}
public SmapleB()
{
normalStr = "This is a normal string B";
Console.WriteLine("This is normal constructor B");
}
}
输出
This is static constructor A
This is a static string A
This is a static string A
分析
程序首先调用SmapleA的静态字符串成员,因此会执行静态构造函数。
当派生类B调用A的静态字符串成员时,由于已经执行过静态构造函数了,所以只会打印staticStr。
代码三
跟代码二相比,值改变main函数中的代码
class Program
{
static void Main(string[] args)
{
SmapleA myA = new SmapleA();
SmapleB myB = new SmapleB();
}
}
输出
This is static constructor A
This is normal constructor A
This is static constructor B
This is normal constructor A
This is normal constructor B
分析
首先是前两行输出,类只要包含静态成员,若没有显试的调用静态构造函数,则.net框架会自动调用静态构造函数。但是要注意先调用静态构造函数,再调用构造函数。
后三行是初始化类B。当初始化类B时,先调用类B的静态构造函数。由于B继承自A,先调用A的无参构造函数,然后调用类B的无参构造函数。