对beforefieldinit的理解

 

今天看了Artech,

关于Type Initializer BeforeFieldInit的问题,看看大家能否给出正确的解释

http://www.cnblogs.com/artech/archive/2008/11/01/1324280.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中没有栈,或者说参与闭包的私有变量不在栈中

 

 

posted @ 2008-11-06 11:24  WXWinter(冬)  阅读(3239)  评论(0编辑  收藏  举报