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中没有栈,或者说参与闭包的私有变量不在栈中

     

     

  • 相关阅读:
    javascript实现禁止右键和F12查看源代码
    网页头部meta标签
    apache多站点vhost.conf配置
    dedecms织梦(一)
    PHP开发微信公众号
    wordpress学习(五)----插件
    wordpress学习(四)---url伪静态简单了解
    wordpress学习(三)-----add_action动作钩子和add_filter()过滤器钩子
    wordpress学习(二)
    原生JS实现addClass,removeClass,toggleClass
  • 原文地址:https://www.cnblogs.com/foundation/p/1327927.html
Copyright © 2011-2022 走看看