小结:
1. 引用类型的实例构造函数
对于引用类型,如果没有显式为其定义任何构造函数,那么,许多编译器(包括c#编译器)将会定义一个默认的无参数构造函数,该构造函数的实现只是调用基类的无参构造函数,如
public class SomeType{
...
}
上述代码等同于下面的代码:
public class SomeType{
public SomeType():base(){ };
}
如果存在继承关系,编译器会自动产生调用基类无参构造函数的代码,沿着继承链一直到System.Object的无参构造函数。但实例构造函数是不能被继承的,只能被当前类使用,不能被子类调用。
2. 值类型实例构造函数
a. 值类型没有默认的无参构造函数,也不允许我们定义无参构造函数,但是允许我们定义带参数的构造函数。
b. 如果定义了带参数的构造函数,则在该构造函数中必须对所有实例字段进行初始化,如果有实例字段没有被初始化,就会报错。
c. 带参构造函数定义之后需要用new显式调用才能执行,否则值类型的字段会保持0或null值。
3. 类型构造函数【静态构造函数】
a. 静态构造函数只能有一个,不能进行重载,不能含参数,静态构造函数的目的是初始化类的静态成员,它只能访问静态成员,不能访问实例成员
b. 静态构造函数的访问限制是私有的,不能为其添加任何访问修饰符,private也不行,这样做是为了防止开发人员调用该方法,静态构造函数的调用是由CLR负责的
c. 即便可以在值类型中定义静态构造函数,但实际上永远不要这样做。
d. CLR保证每个应用程序域的静态构造函数只执行一次,且是线程安全的。即如果有多个线程同时访问静态构造函数,这时就需要一个线程同步锁,那么只有一个线程可以获得同步锁,其他线程将被阻塞。第一个线程执行静态构造函数的代码,当第一个线程释放了该函数后,其他线程将被唤醒,然后发现构造函数的代码已经被执行过了,因此,这些线程就不再执行构造函数的代码了,只是简单的返回。
例子:
public class A { private static Int32 i = 0; static A() { i++; Console.WriteLine("in static constructor: {0}", i); } public A() { i++; Console.WriteLine("in public constructor: {0}", i); } } class Program { static void Main(string[] args) { A a = new A(); //第一次实例化,CLR先调用static构造函数,i的值为1,再调实例构造函数,i的值为2
A b = new A(); //第二次实例化,static构造函数已不会再被执行,这次只会调用实例构造函数,i的值为3
Console.ReadKey(); } }