您有任何想法,为什么以下代码:
public class A
{
public static int i = B.i + 1;
}
public class B
{
public static int i = A.i + 1;
}
有:
int aa = A.i;
int bb = B.i;
说aa = 2(!!!)和bb = 1.
我脑子里有一个堆叠溢出! 据我所知,递归在静态方法上停止,但为什么呢? 如果你将int i重新编写为getter(为了调试并理解它为什么会这样工作),你会得到堆栈溢出异常。
答案 0 :(得分:6)
毫无疑问,执行正在发生:
首先运行B.i
静态初始值设定项,然后设置B.i = A.i + 1
。由于A.i
尚未初始化,A.i
等于default(int)
,即0
。 B.i
获取值1
。
A.i
静态初始化程序运行第二个,并设置A.i = B.i + 1 = 2
。
由于静态初始化程序以未定义的顺序运行,因此每次运行时,您可能会发现其他字段为2
,或者当您对代码进行其他结构更改时,它们会切换。但是,应始终为2
,其中一个应始终为1
。
P.S。这与多态性无关。
编辑:为了进一步了解静态初始化器和构造函数的时序,您可能需要检查this relevant portion of the C# specification.
答案 1 :(得分:4)
字段不像属性getter。它只存储数据,而不是任何操作。实际上,初始化将被移动到另一个方法(静态构造函数,.cctor
),它将初始化类中的静态变量。
一开始,两者都将等于0.在您第一次访问A.i
之前,类.cctor
的方法A
会运行。它首次尝试访问B.i
,这将导致执行类B
的静态构造函数。 .cctor
的{{1}}将尝试访问B
,但由于这不是第一次访问字段,A.i
的静态构造函数不再跑了。它只获取A
的当前值,该值仍为0.因此,A
完成执行并且控制权返回B.i
时,B..cctor
将等于1。它会看到值A..cctor
并将其加1并将其存储在B.i
中。因此,A.i
将等于2(1 + 1),A.i
将等于1.
唯一的保证是静态构造函数在之前被称为,访问该类的任何静态成员。
答案 2 :(得分:1)
这是正在发生的事情。
非常重要的一点是,静态属性被初始化为默认值,然后然后静态初始化程序运行。
就个人而言,我尽可能避免静态初始化,静态和其他。有太多的陷阱。