2009-12-21 60 views
3

何时分配静态变量,即何时声明类或创建对象时?.net中的静态变量分配时间

+0

请参阅此相关的问题:http://stackoverflow.com/questions/218461/difference-initializing-static-variable-inline-or-in-static-constructor-in-c – 2009-12-21 15:31:59

回答

6

它被编译成静态构造函数。因此,当任何人第一次创建该类的对象或调用静态方法或属性时,就会进行初始化。

编辑:如果初始化发生在自己的静态构造函数代码之前(以及其他一些边界情况),当它对你很重要时,请通过divo检查注释中的链接。

+6

它不那么简单。 Jon Skeet有关于此的综合性文章,请参阅http://www.yoda.arachsys.com/csharp/beforefieldinit.html。在没有静态构造函数的类中,类型初始值设定项可能会在程序集被加载时执行,或者当该类型的静态方法被执行,或者甚至只有当类型的第一个字段被访问时才会运行。 – 2009-12-21 15:29:56

+0

这是一个非常有趣的链接,divo。谢谢。我认为在大多数实际的目的中,我的答案是可以的,但似乎比我想象的要多。 – 2009-12-21 15:35:39

+0

是的,正如Jon所写的:“很多类实际上并不需要许多C#程序员所承担的行为 - 实际上,大多数人不需要知道其中的差异。”但它可能正是这些边缘案例引发的意外错误。 – 2009-12-21 15:40:05

4

首次类被访问....

+1

虽然你的回答是“足够好”它可以更好。 – ChaosPandion 2009-12-21 15:19:00

0

只要调用static(type)构造函数就会分配静态变量。当您在方法执行之前调用任何第一次引用类型的方法时,会发生这种情况。

+0

只有*是*静态类型的构造函数时才是如此。 – 2009-12-21 15:35:18

+0

任何显式字段初始化都将在构造函数体之前编译到构造函数中。如果没有声明的静态构造函数,编译器会生成一个。 – ironic 2009-12-21 15:52:15

+0

@ironic:不,情况并非如此。如果没有静态构造函数,该类将被标记为'beforefieldinit'标志,这意味着执行类型初始化程序的时间不确定。 – 2009-12-21 16:03:33

2

正如其他答案已经表明,这将发生在类型(静态)构造函数。如果你的类没有明确定义的类型构造函数,那么编译器会为你生成一个类型构造函数。但是,确定何时调用该构造函数的确切时间有点多。

如果您的类未定义显式类型构造函数,例如

public class Foo 
{ 
    public static int Bar = 1; 
} 

然后C#编译器将生成一个构造函数并使用beforefieldinit标志发出类定义。这将导致JIT编译器保证类型构造函数在第一次使用该类型的成员之前被调用,但这次是非确定性的,即不可能确切地知道何时会发生这种情况,并且它可能在比首次使用类型成员时要早得多。

如果你的类声明了一个显式的类型构造函数,例如

public class Foo 
{ 
    public static int Bar; 
    static Foo() 
    { 
     Bar = 1; 
    } 
} 

然后编译器会发出IL而没有beforefieldinit标志。在这种情况下,JIT编译器将在确定的时间调用类型构造器,即紧接在第一类型成员访问之前。

前者JIT行为称为前场-INIT语义和后者作为精确 sematntics。了解两者之间的差异很重要,因为在某些情况下,它们可能会有重大的性能影响。

+0

nitpick:对于'beforefieldinit'而言,重要的是静态构造函数是否存在,而不是*你的字段是否在构造函数中初始化。如果类没有静态构造函数,那么它将被编译器标记为'beforefieldinit';如果该类有一个静态构造函数,那么它将不会被标记为'beforefieldinit',而不管它的字段被初始化的位置。 – LukeH 2009-12-21 15:51:19

+0

仍然这应该是被接受的答案:-) – 2009-12-21 15:52:26

+0

@Luke - 感谢指出。 Nitpicking是好的;-)已编辑 – 2009-12-22 07:17:03