c#静态构造函数

  c#静态构造函数,又称类构造函数。它是属于类的,不属于任何一个类的实例。它具有以下特点:
1、以static定义的,无访问修饰符,无返回类型,无参数的构造函数,如: 

Code:
  1. class test   
  2.         {   
  3.             /// <summary>   
  4.             /// 静态构造函数/类构造函数   
  5.             /// </summary>   
  6.             static test()   
  7.             {   
  8.             }   
  9.         }  

2、不能通过代码显式的调用静态构造函数
3、静态构造函数在类的静态成员第一次访问或第一个类实例创建之前由系统调用
4、静态构造函数最多运行一次
5、静态构造函数须显式定义,若不定义,则不存在默认静态构造函数:此特点后面将详细说明
6、一个类中最多只能定义一个静态构造函数
7、静态构造函数主要完成的是静态数据成员的初始化工作,若定义静态数据成员的时候进行初始化,同时在静态构造函数中进行了初始化,则以静态构造函数的初始化为准。 

Code:
  1. C#代码:
  2. class Test   
  3.     {   
  4.         public static string x = "a";   
  5.   
  6.         static Test()   
  7.         {   
  8.             x = "b";   
  9.         }           
  10.     }   
  11.   
  12. IL代码:   
  13. .class private auto ansi Test   
  14.     extends [mscorlib]System.Object   
  15. {   
  16.     .method private hidebysig specialname rtspecialname static void .cctor() cil managed   
  17.     {   
  18.         .maxstack 8   
  19.         L_0000: ldstr "a"  
  20.         L_0005: stsfld string StaticTest.Test::x   
  21.         L_000a: nop    
  22.         L_000b: ldstr "b"  
  23.         L_0010: stsfld string StaticTest.Test::x   
  24.         L_0015: nop    
  25.         L_0016: ret    
  26.     }   
  27.   
  28.     .method public hidebysig specialname rtspecialname instance void .ctor() cil managed   
  29.     {   
  30.         .maxstack 8   
  31.         L_0000: ldarg.0    
  32.         L_0001: call instance void [mscorlib]System.Object::.ctor()   
  33.         L_0006: ret    
  34.     }   
  35.   
  36.   
  37.     .field public static string x   
  38.   
  39. }   
  40.   
  41.     

从上面的C#转换为IL代码可以看出,x被赋值了两次,一次是a,一次是b,但是最后起作用的是b。


对于静态构造函数,很多的介绍中都认为存在默认的静态构造函数,我个人认为这是不准确的。因为很多人都认为静态构造函数和转换的IL代码中的.cctor方法是对应的。其实不然,.cctor可以说是静态成员初始化器或是类初始化器,但并不是所有的类在转化成IL代码的时候都会生成.cctor方法;而静态构造函数会影响.cctor生成的代码,同时会通过取消IL代码中的"beforefieldinit"而影响.cctor方法的调用时机。下面就分别从几个类生成的IL代码情况,对问题进行说明。
1、无静态构造函数、静态成员的空类:有beforefieldinit标记,无.cctor函数 

Code:
  1. C#代码:   
  2. class Test   
  3.     {   
  4.     }   
  5. 转化的IL代码:   
  6. .class private auto ansi beforefieldinit Test   
  7.     extends [mscorlib]System.Object   
  8. {   
  9.     .method public hidebysig specialname rtspecialname instance void .ctor() cil managed   
  10.     {   
  11.         .maxstack 8   
  12.         L_0000: ldarg.0    
  13.         L_0001: call instance void [mscorlib]System.Object::.ctor()   
  14.         L_0006: ret    
  15.     }   
  16. }   

2、无静态构造函数、有静态成员但声明时未进行初始化:与1的结果一样有beforefieldinit标记,无.cctor函数 

Code:
  1. C#代码:   
  2.  class Test   
  3.     {   
  4.         public static string x;           
  5.     }   
  6. 转化的IL代码:   
  7. .class private auto ansi beforefieldinit Test   
  8.     extends [mscorlib]System.Object   
  9. {   
  10.     .method public hidebysig specialname rtspecialname instance void .ctor() cil managed   
  11.     {   
  12.         .maxstack 8   
  13.         L_0000: ldarg.0    
  14.         L_0001: call instance void [mscorlib]System.Object::.ctor()   
  15.         L_0006: ret    
  16.     }   
  17.     .field public static string x   
  18. }   
  19.   
  20.     

3、无静态构造函数、有静态成员并已初始化:有beforefieldinit标记、有.cctor函数

Code:
  1. C#代码:   
  2. class Test   
  3.     {   
  4.         public static string x="a";           
  5.     }   
  6. 转化的IL代码:   
  7. .class private auto ansi beforefieldinit Test   
  8.     extends [mscorlib]System.Object   
  9. {   
  10.     .method private hidebysig specialname rtspecialname static void .cctor() cil managed   
  11.     {   
  12.         .maxstack 8   
  13.         L_0000: ldstr "a"  
  14.         L_0005: stsfld string StaticTest.Test::x   
  15.         L_000a: ret    
  16.     }   
  17.     .method public hidebysig specialname rtspecialname instance void .ctor() cil managed   
  18.     {   
  19.         .maxstack 8   
  20.         L_0000: ldarg.0    
  21.         L_0001: call instance void [mscorlib]System.Object::.ctor()   
  22.         L_0006: ret    
  23.     }   
  24.     .field public static string x   
  25. }   
  26.   

4、有静态构造函数、无静态成员的类:无beforefieldinit标记、有.cctor函数

Code:
  1. C#代码:   
  2. class Test   
  3.     {   
  4.         //public static string x="a";   
  5.         static Test()   
  6.         {   
  7.         }   
  8.     }   
  9. 转化的IL代码:   
  10. .class private auto ansi Test   
  11.     extends [mscorlib]System.Object   
  12. {   
  13.     .method private hidebysig specialname rtspecialname static void .cctor() cil managed   
  14.     {   
  15.         .maxstack 8   
  16.         L_0000: nop    
  17.         L_0001: ret    
  18.     }   
  19.     .method public hidebysig specialname rtspecialname instance void .ctor() cil managed   
  20.     {   
  21.         .maxstack 8   
  22.         L_0000: ldarg.0    
  23.         L_0001: call instance void [mscorlib]System.Object::.ctor()   
  24.         L_0006: ret    
  25.     }   
  26. }   

通过上面的分析,可以了解:无静态构造函数的时候,类生成的IL代码中一定有beforefieldinit标记,但不一定有.cctor函数;有静态构造函数的时候,生成的IL代码中必定有.cctor函数,类中无beforefieldinit标记;.cctor函数是负责静态成员的初始化的,如果声明时和在静态构造函数中都有初始化,则两者会合并到.cctor函数中,声明的初始化在前,静态构造函数的初始化在后。

beforefieldinit标记主要是用来决定.cctor调用时机。
如果未声明类的静态构造函数,则会设置beforefieldinit标记,此时的.cctor函数会交给CLR进行调用,CLR可以选择程序集加载到第一访问类型(包括访问静态成员和类实例)的这个时间段内的任何时间点调用.cctor函数,此时较难掌握.cctor运行时机。
如果声明了类的静态构造函数,则将不设置beforefieldinit标记,此时.cctor是在第一次使用类之前调用,可以顺利跟踪具体的时机。
以上两种方式在速度上存在较大的差别,其中设置了beforefieldinit标记的类,在类型初始化器(.cctor)的运行性能上优于未设置beforefieldinit的类。具体可参考:
blog.csdn.net/liuyimu/archive/2010/04/29/5544222.aspx
www.cnblogs.com/carysun/archive/2009/09/08/beforefieldinit.html
csharpindepth.com/Articles/General/Beforefieldinit.aspx

静态构造函数在性能上不如未设置静态构造函数的情况,那为什么还是建议大家使用静态构造函数初始化各类静态成员呢?个人认为,主要是通过静态构造函数,可以很好的把握初始化静态成员的时机,虽然在性能上有点劣势,但是因为只初始化一次,这点性能上的影响微乎其微。可以不予考虑。可参看Effective C#原则13

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值