静态构造函数和BeforeFieldInit? [英] static constructors and BeforeFieldInit?

查看:253
本文介绍了静态构造函数和BeforeFieldInit?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果一个类型没有静态构造函数,字段初始将执行   之前的类型为使用 - 或任何时候,在更早的心血来潮   运行时

If a type has no static constructor, field initializers will execute just prior to the type being used— or anytime earlier at the whim of the runtime

为什么这个code:

void Main()
{ 
  "-------start-------".Dump();
   Test.EchoAndReturn("Hello");
  "-------end-------".Dump();

}

 class Test
{
    public static string x = EchoAndReturn ("a");
    public static string y = EchoAndReturn ("b");
    public static string EchoAndReturn (string s)
    {
        Console.WriteLine (s);
        return s;
    }
}

收益率:

-------start-------
a
b
Hello
-------end-------

而这code:

while this code :

void Main()
{ 
  "-------start-------".Dump();
   var test=Test.x;
  "-------end-------".Dump();

}

收益率

a
b
-------start-------
-------end-------

A B 的顺序被理解。但为什么与静态方法处理是不同的静态字段

The order of a and b is understood. but why dealing with static method is different than static field.

我的意思是,为什么的启动结束的线路都在用静态方法VS静态字段不同的位置?我的意思是 - 在这两种情况下他必须初始化这些字段...那么,为什么

I mean why the start and end lines are in different locations with static methods vs static fields ? I mean - in both situation he's got to initialize those fields...so why ?

(我知道我可以添加静态构造函数,这使得它是同一个 - 但我要问关于这种特殊情况下)

(PS转储()就像console.write)

推荐答案

释放JIT的行为(从4.0 IIRC)不运行静态初始化除非该方法要调用触摸静态字段。这可能意味着静态字段的不是初始化。如果我运行你的第一个code在发布调试器之外,我得到:

The behavior of the release JIT is (from 4.0 IIRC) not to run the static initializer unless the method you are calling touches static fields. This can mean the static fields are not initialized. If I run your first code in release outside of the debugger, I get:

-------start-------
Hello
-------end-------

如果我附加了调试器(释放),或在调试版本(带或不带调试器附加)运行它,我得到:

If I run it with the debugger attached (release), or in a debug build (with or without debugger attached), I get:

-------start-------
a
b
Hello
-------end-------

到目前为止,非常有趣。对于为什么你:

So far so interesting. For why you get:

a
b
-------start-------
-------end-------

它看起来像每个方法JIT基本上采取了在这种情况下运行的静态构造函数的责任。您可以通过添加看到这样的:

it looks like the per-method JIT is essentially taking responsibility for running the static constructor in this scenario. You can see this by adding:

if(NeverTrue()) { // method that returns false
        "-------start-------".Dump();
        var test = Test.x;
        "-------end-------".Dump();
}

这将打印(甚至在释放无调试器)

which will print (even in release without the debugger)

a
b

这样的可能的访问领域是关键。如果我们改变 Test.x 将呼叫该的不访问字段的方法的(和删除 NeverTrue ()的事情),那么我们得到的没有输出任何的。

so the possibility of accessing fields is key. If we change Test.x to be a call to a method that doesn't access fields (and remove the NeverTrue() thing), then we get no output whatsoever.

所以:在某些版本的CLI的,静态初始化的执行可能会延迟到包含提到的任何字段(它不检查是否该领域具有初始化)方法JIT步

So: in some versions of the CLI, the execution of static initializers may be deferred to the JIT-step of methods that contain mentions to any field (it doesn't check whether that field has an initializer).

我们甚至可以创建对象的实例,但不运行的静态初始化,只要我们不碰静态字段:

We can even create instances of objects without running the static initializer, as long as we don't touch static fields:

 public Test()
 {
     a = "";
 }
 string a;

"-------start-------".Dump();
new Test();
"-------end-------".Dump();

刚刚打印(释放,没有调试器):

prints just (release, no debugger):

-------start-------
-------end-------

不过!我们不应该建什么,取决于这个时机:

HOWEVER! We should not build anything that depends on this timing:

  • 在它.NET版本之间的更改
  • 在可能的平台之间也发生变化(86,64,CF,SL,.NETCore等)
  • 可以根据调试器是否连接发生变化,无论是调试/发行版本

这篇关于静态构造函数和BeforeFieldInit?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆