C# 类型构造器
🏷️ 《CLR via C#》
类型构造器 type constructor(静态构造器 static constructor)
类型构造器可应用于接口(虽然C#编译器不允许)、引用类型和值类型。
类型构造器的作用是设置类型的初始状态。
类型构造器总是私有的(C# 自动把它们标记为 private
)。
cs
class SomeRefType
{
static int MaxCount;
static SomeRefType()
{
MaxCount = 100;
}
}
类型构造器的调用
JIT 编译器在编译一个方法时,会查看代码中都引用了哪些类型。
任何一个类型定义了类型构造器,JIT 编译器都会检查针对当前 AppDomain,是否已经执行了这个类型构造器。
如果类型构造器从未执行,JIT 编译器会在它生成的本机(native)代码中添加对类型构造器的调用。
如果类型构造器已经执行,JIT 编译器就不添加对它的调用。
多个线程可能会同时执行到相同的类型构造器方法。
CLR 希望确保在每个 AppDomain 中,一个类型构造器只执行一次。
在调用类型构造器时,调用线程要获取一个互斥线程同步锁。
单个线程中的两个类型构造器包含相互引用的代码可能出问题。
如果类型构造器抛出未处理的异常,CLR 会认为类型不可用。试图访问该类型的任何字段或方法都会抛出 System.TypeInitializationException
异常。
类型构造器中的代码只能访问类型的静态字段,并且它的常规用途就是初始化这些字段。
C#提供了一种简单的语法来初始化类型的静态字段。
cs
class SomeRefType
{
static int MaxCount = 50;
}
上面的代码相当于
cs
class SomeRefType
{
static int MaxCount;
static SomeRefType()
{
MaxCount = 50;
}
}
如果在静态字段和类型构造器中都赋值的话,以哪个为准呢?
cs
class SomeRefType
{
static int MaxCount = 50;
static SomeRefType()
{
MaxCount = 100;
}
}
查看生成的 IL 代码
cs
.class /*02000003*/ private auto ansi ConsoleApp1.SomeRefType
extends [mscorlib/*23000001*/]System.Object/*01000010*/
{
.field /*04000001*/ public static int32 MaxCount
.method /*06000003*/ private hidebysig specialname rtspecialname static
void .cctor() cil managed
// SIG: 00 00 01
{
// 方法在 RVA 0x2065 处开始
// 代码大小 16 (0x10)
.maxstack 8
IL_0000: /* 1F | 32 */ ldc.i4.s 50
IL_0002: /* 80 | (04)000001 */ stsfld int32 ConsoleApp1.SomeRefType/*02000003*/::MaxCount /* 04000001 */
IL_0007: /* 00 | */ nop
IL_0008: /* 1F | 64 */ ldc.i4.s 100
IL_000a: /* 80 | (04)000001 */ stsfld int32 ConsoleApp1.SomeRefType/*02000003*/::MaxCount /* 04000001 */
IL_000f: /* 2A | */ ret
} // end of method SomeRefType::.cctor
.method /*06000004*/ public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// SIG: 20 00 01
{
// 方法在 RVA 0x205c 处开始
// 代码大小 8 (0x8)
.maxstack 8
IL_0000: /* 02 | */ ldarg.0
IL_0001: /* 28 | (0A)000011 */ call instance void [mscorlib/*23000001*/]System.Object/*01000010*/::.ctor() /* 0A000011 */
IL_0006: /* 00 | */ nop
IL_0007: /* 2A | */ ret
} // end of method SomeRefType::.ctor
} // end of class ConsoleApp1.SomeRefType
可以看到只生成了一个 cctor
(类型构造器)方法,先将 MaxCount
赋值为 50,然后再赋值为 100。