zoukankan      html  css  js  c++  java
  • 对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中没有栈,或者说参与闭包的私有变量不在栈中

     

     

  • 相关阅读:
    Aurora 数据库支持多达五个跨区域只读副本
    Amazon RDS 的 Oracle 只读副本
    Amazon EC2 密钥对
    DynamoDB 读取请求单位和写入请求单位
    使用 EBS 优化的实例或 10 Gb 网络实例
    启动 LAMP 堆栈 Web 应用程序
    AWS 中的错误重试和指数退避 Error Retries and Exponential Backoff in AWS
    使用 Amazon S3 阻止公有访问
    路由表 Router Table
    使用MySQLAdmin工具查看QPS
  • 原文地址:https://www.cnblogs.com/foundation/p/1327927.html
Copyright © 2011-2022 走看看