上篇说到了如果一个类有静态成员但没初始化,系统将不产生一个内联的静态构造函数,如果定义了静态成员且初始化了,编译器将生成一个内联的构造函数(当然了你没有显示定义静态构造函数的情况下)今天我要说的是编译器什么时候应该去调用静态构造函数
上面我红框,框起来的static 有与没有对程序的结果及执行顺序有很大的影响(相传是一道C井面试题 )。有static 打印结果2, 1 程序将在调用WriteLine时先执行A的构造,再B的构造; 没有static 时将打印1,2 程序会在进入Main函数之前先调用B的构造。我在网上也找了很多相关方面的资料和自己的一些代码测试,主要意思是如果没有显示定义构造函数,初始代码将在Main函数之前初始化,到底是在Main之前的哪一个语句编译器没有规定, 如果显示定义了静态构造函数, 程序将在你要创建类实例或引用静态字段或方法前调用。我也看了Jeffrey Richter 写的 CLR Via C Sharp 这本书关于这方面的一些讲解,一般来说他写的书还是有点深入的,我看的是英文版本,在这本书里他提到了静态构造函数对程序情能的影响 (在显示定义了构造函数时,静态构造函数的代码将在初始化时内嵌到你的代码中, 所以在一个很大的循环里的话将影响性能, Jeffrey Richter在书中举了一个例子)下面是我从书中摘录的部分,也推荐大家去看一下这本书。
In the previous section, I mentioned that calling a type constructor is a tricky thing. And I explained some of the trickiness about it: the JIT compiler has to decide whether to emit the code to call it, and the CLR ensures that calls to it are thread-safe. As it turns out, this is the just the beginning of the tricky stuff. There is more about this that is performance related. As discussed already, when compiling a method, the JIT compiler determines whether it must emit a call to execute a type constructor into the method. If the JIT compiler decides to emit the call, it must decide where it should emit the call. There are two possibilities here:
• The JIT compiler can emit the call immediately before code that would create the first instance of the type or immediately before code that accesses a noninherited field or member of the class. This is called precise semantics because the CLR will call the type constructor at precisely the right time.
• The JIT compiler can emit the call sometime before code that accesses a noninherited static field. This is called before-field-init semantics because the CLR guarantees only that the static constructor will run some time before the static field is accessed; it could run much earlier.
The before-field-init semantics is preferred since it gives the CLR a lot of freedom as to when it can call the type constructor, and the CLR takes advantage of this whenever possible to produce code that executes faster. For example, the CLR might pick different times to call the type constructor based on whether the type is loaded in an AppDomain or loaded domain- neutral or whether the code is being JIT compiled or NGen'd. By default, language compilers choose which of these semantics makes the most sense for the type you're defining and informs the CLR of this choice by setting the beforefieldinit flag inthe row of the type definition metadata table. In this section, I'll focus on what the C# com- piler does and how this impacts performance. Let's start by examining the following code:
留言与评论(共有 0 条评论) |