CLR via C# 方法 类型构造器

除了实例构造器,CLR还支持类型构造器(type constructor),也称为静态构造器(static constructor)、类构造器(class constructor)或者类型初始化器(type initializer)。类型构造器可用于接口(虽然C#编译器不允许)、引用类型和值类型。实例构造器的作用是设置类型的实例的初始状态。对应地,类型构造器的作用是设置类型的初始状态。类型默认没有定义类型构造器。如果定义,也只能定义一个。此外,类型构造器永远没有参数。

可以看出,定义类型构造器类似于定义无参实例构造器,区别在于必须标记为static。此外类型构造器总是私有的;C#自动把它们标记为private。事实上,如果在源代码中显式将类型构造器标记为private(或其他访问修饰符),C#编译器会提示消息:

之所以必须私有,是为了防止任何开发人员写的代码调用它,对它的调用总是由CLR负责。

//--

类型构造器的调用比较麻烦。JIT编译器在编译一个方法时,会查看代码中都引用了哪些类型。任何一个类型定义了类型构造器,JIT编译器都会检查针对当前AppDomain,是否已经执行了这个类型构造器。如果构造器从未执行,JIT编译器会在它生成的本机(native)代码中添加对类型构造器的调用。如果类型构造器已经执行,JIT编译器就不添加对它的调用,因为它知道类型已经初始化好了。

现在,当方法被JIT编译完毕后,线程开始执行它,最终会执行到调用类型构造器的代码。事实上,多个线程可能同时执行相同的方法。CLR希望确保在每个AppDomain中,一个类型构造器只执行一次。为了保证这一点,在调用类型构造器时,调用线程要获取一个互斥线程同步锁。这样一来,如果多个线程试图同时调用某个类型的静态构造器,只有一个线程才可以获得锁,其他线程会被阻塞(blocked)。第一个线程会执行静态构造器中的代码。当第一个线程离开构造器后,正在等待的线程将被唤醒,然后发现构造器的代码已被执行过。因此这些线程不会再次执行代码,将直接从构造器方法返回。除此之外,如果再次调用这样的一个方法,CLR知道类型构造器已被执行过,从而确保构造器不被再次调用。

//--

重要提示:虽然能在值类型中定义类型构造器,但永远都不要真的那么做,因为CLR有时不会调用值类型的静态类型构造器。

//--

注意:由于CLR保证一个类型构造器在每个AppDomain中只执行一次,而且(这种执行)是线程安全的,所以非常适合在类型构造器中初始化类型需要的任何单实例(Singleton)对象。

//--

单个线程中的两个类型构造器包含相互引用的代码可能出现问题。

例如,假定ClassA的类型构造器包含了引用ClassB的代码,ClassB的类型构造器包含了引用ClassA的代码。

在这种情况下,CLR仍然保证每个类型构造器的代码只被执行一次;但是,完全有可能在ClassA的类型构造器还没有执行完毕的前提下,就开始执行ClassB的类型构造器。因此,应尽量避免写会造成这种情况的代码。事实上,由于CLR负责类型构造器的调用,所以任何代码都不应要求以特定的顺序调用类型构造器。

最后,如果类型构造器抛出未处理的异常,CLR会认为类型不可用。试图访问该类型的任何字段或方法都会抛出System.TypeInitializationException异常。

//--

类型构造器中的代码只能访问类型的静态字段,并且它的常规用途就是初始化这些字段。

生成上述代码时,编译器自动为SomeType生成一个类型构造器。就像下面:

类型构造器不应调用基类型的类型构造器。这种调用之所以没必要,是因为类型不可能有静态字段是从基类型分享或继承的。

//--

在这个例子中,C#编译器只生成一个类型构造器方法。它首先将s_x初始化为5,再把它修改成10。换言之当C#编译器为类型构造器生成IL代码时,它首先生成的是初始化静态字段所需的代码,然后才会添加你的类型构造器方法中显式包含的代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值