对beforefieldinit的理解
2008-11-06 11:24
465 查看
今天看了Artech,
关于Type Initializer和 BeforeFieldInit的问题,看看大家能否给出正确的解释
/article/1308541.html
,的文章,并看了Artech,TerryLee,Anytao几位高人的讨论,对NET的理解又加深不少,心情不错,也写一篇对于beforefieldinit理解的文章
原文中的一段例子代码
using System; namespace Artech.TypeInitializerDemo { class Program { static void Main() { Console.WriteLine("Start ..."); Foo.GetString("Manually invoke the static GetString() method!"); string field = Foo.Field; } } class Foo { public static string Field = GetString("Initialize the static field!"); public static string GetString(string s) { Console.WriteLine(s); return s; } } } |
出现这种情况的原因是beforefieldinit关键字的使用.
下面是地两段用IL实现上面C#的例子的代码,匹别只是一段使用了beforefieldinit,一段没使用
例1:用IL实现上面C#的例子,使用beforefieldinit
这是上面C#的例子的默认实现方式.assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) .ver 2:0:0:0 } .assembly myTest { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .hash algorithm 0x00008004 .ver 0:0:0:0 } .module myTest.dll .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 .corflags 0x00000001 .namespace myTest { .class public auto ansi beforefieldinit Test1 extends [mscorlib]System.Object { .method private hidebysig specialname rtspecialname static void .cctor() cil managed { .maxstack 8 L_0000: ldstr "Initialize the static field!" L_0005: call string myTest.Test1::GetString(string) L_000a: stsfld string myTest.Test1::Field L_000f: ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void [mscorlib]System.Object::.ctor() L_0006: ret } .method public hidebysig static string GetString(string s) cil managed { .maxstack 1 .locals init ( [0] string CS$1$0000) L_0000: nop L_0001: ldarg.0 L_0002: call void [mscorlib]System.Console::WriteLine(string) L_0007: nop L_0008: ldarg.0 L_0009: stloc.0 L_000a: br.s L_000c L_000c: ldloc.0 L_000d: ret } .field public static string Field } } |
编译 ilasm c:\myTest.txt /dll |
在C#中引用上面编译好的Dll class Program { static void Main(string[] args) { Console.WriteLine("Start ..."); myTest.Test1.GetString("Manually invoke the static GetString() method!"); string field = myTest.Test1.Field; Console.Read(); } } |
运行结果与上面C#的例子一样 |
在VS加个断点,可以看到代码还没运行到[ string field = myTest.Test1.Field;] ,但[myTest.Test1.Field]已经有值了 |
例2:用IL实现上面C#的例子,不使用beforefieldinit
.assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) .ver 2:0:0:0 } .assembly myTest { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .hash algorithm 0x00008004 .ver 0:0:0:0 } .module myTest.dll .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 .corflags 0x00000001 .namespace myTest { .class public auto ansi Test1 extends [mscorlib]System.Object { .method private hidebysig specialname rtspecialname static void .cctor() cil managed { .maxstack 8 L_0000: ldstr "Initialize the static field!" L_0005: call string myTest.Test1::GetString(string) L_000a: stsfld string myTest.Test1::Field L_000f: ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void [mscorlib]System.Object::.ctor() L_0006: ret } .method public hidebysig static string GetString(string s) cil managed { .maxstack 1 .locals init ( [0] string CS$1$0000) L_0000: nop L_0001: ldarg.0 L_0002: call void [mscorlib]System.Console::WriteLine(string) L_0007: nop L_0008: ldarg.0 L_0009: stloc.0 L_000a: br.s L_000c L_000c: ldloc.0 L_000d: ret } .field public static string Field } } |
编译 ilasm c:\myTest.txt /dll |
在C#中引用上面编译好的Dll class Program { static void Main(string[] args) { Console.WriteLine("Start ..."); myTest.Test1.GetString("Manually invoke the static GetString() method!"); string field = myTest.Test1.Field; Console.Read(); } } |
这个结果是与通常的预期一致 |
同样在VS加个断点,可以看到[myTest.Test1.Field]无值 |
beforefieldinit到底要做什么
先分析一下[例1]的现象,Test1是何时被构造的,静态构造会在类第一次访问时进行,但是[例1]的第一次访问是在[string field = myTest.Test1.Field;]中,可是构造为何会发生在[
Console.WriteLine("Start ...");]之前
下面是我分析出的结论,方法在加载前会先将方法体内所有变量筛选一便,如果发现有特殊标记(如beforefieldinit),会将该变量提前放到一个缓存中,也就是说Main方法在初始化时,就已经去访问[Field]了,
还有,我觉得field不在方法体的栈中,有时我感NET中没有栈,或者说参与闭包的私有变量不在栈中
相关文章推荐
- [C#]BeforeFieldInit与类静态构造函数
- 关于静态构造函数和BeforeFieldInit
- [C#]BeforeFieldInit 与类静态构造函数
- 关于静态构造函数和BeforeFieldInit
- beforefieldinit修饰符是干嘛用的
- [原创] 关于Type Initializer和 BeforeFieldInit的问题,看看大家能否给出正确的解释
- BeforeFieldInit解析(zz)
- 关于Type Initializer和 BeforeFieldInit的问题,看看大家能否给出正确的解释
- C#中的BeforeFieldInit
- 深入理解iOS API系列(一) textField:shouldChangeCharactersInRange:replacementString:
- Java中构造代码块和成员变量初始化的顺序关系2之 Cannot reference a field before it is defined
- 深入理解Android(06)——Java世界的入口ZygoteInit
- Ontology ---------- the definition of philosophy and in IT field
- A previous installation of Qt5 Visual Studio Add-in was detected. Please uninstall it before running
- A previous installation of Qt5 Visual Studio Add-in was detected. Please uninstall it before running
- com.sun.faces.lifecycle.ELResolverInitPhaseListener.beforePhase
- 深入理解iOS API系列(一) textField:shouldChangeCharactersInRange:replacementString:
- 深入理解iOS API系列(一) textField:shouldChangeCharactersInRange:replacementString:
- 对GPIO_Init(GPIOx,&GPIO_InitStructure)的理解
- 【论文理解】Where to Buy It: Matching Street Clothing Photos in Online Shops