C# 两个类的静态成员相互引用

发布于 2024-08-31 18:47:38 字数 345 浏览 4 评论 0原文

我想知道为什么这段代码不会以无限递归结束。我猜它与静态成员自动初始化为默认值有关,但是有人可以告诉我“一步一步”“a”如何获得 2 的值和 1 的“b”值吗?

public class A
{
    public static int a = B.b + 1;
}
public class B
{
    public static int b = A.a + 1;
}

static void Main(string[] args)
{
    Console.WriteLine("A.a={0}, B.b={1}", A.a, B.b); //A.a=2, B.b=1
    Console.Read();
}

I wonder why this code doesn't end up in endless recursion. I guess it's connected to the automatic initialization of static members to default values, but can someone tell me "step by step" how does 'a' get the value of 2 and 'b' of 1?

public class A
{
    public static int a = B.b + 1;
}
public class B
{
    public static int b = A.a + 1;
}

static void Main(string[] args)
{
    Console.WriteLine("A.a={0}, B.b={1}", A.a, B.b); //A.a=2, B.b=1
    Console.Read();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

最初的梦 2024-09-07 18:47:39

有趣的是,当我更改示例代码中的输出顺序时:

    Console.WriteLine("B.b={0} A.a={1}", B.b, A.a);

我得到了相反的结果:

B.b=2 A.a=1

所以看起来这与访问它们的顺序有关

因此,考虑到输出可以通过添加以下之一的早期使用来改变变量看起来像这样递归定义的值是一个坏主意(TM):-)

Interestingly when I changed the order of output in your sample code around:

    Console.WriteLine("B.b={0} A.a={1}", B.b, A.a);

I got the opposite results:

B.b=2 A.a=1

So it looks like it is to do with the order they are accessed

So, given that the output could change by adding an early usage of one of the variables it seems like such recursively defined values is A BAD IDEA(TM) :-)

超可爱的懒熊 2024-09-07 18:47:39

由于 Aa 在 Console.WriteLine 中首先被引用,因此它首先被加载,这导致 B 加载时 Aa 的值为 0 => Bb = 1 => Aa 变成 2

反转打印并观察它以相反的方式发生。

Since A.a is referenced first in the Console.WriteLine, its loaded first, which causes B to be loaded with the Value of A.a as 0 => B.b = 1 => A.a becomes 2

Reverse the print and watch it happen the other way.

乖不如嘢 2024-09-07 18:47:38

我假设:

  • 查询Aa,这会导致A静态初始化器触发。
  • 这会访问Bb,导致B 静态初始化程序
  • >查询触发 Aa 的 ;类型初始值设定项已激活(但尚未发生赋值),因此字段(尚未赋值)被读取为 0
  • 0 + 11,被赋值给Bb <========================== ==
  • 我们现在退出 B cctor 并返回到 A cctor
  • 1 + 1 is 2,被分配给Aa <============================
  • 我们现在退出 A cctor
  • Aa,返回
  • 对于我们查询的 2 (WriteLine)(在 WriteLine 上) >) Bb; cctor 已经被触发,所以我们看到 1

I would suppose:

  • A.a is queried, which causes the A static initializer to fire
  • This accesses B.b, causing the B static initializer to fire
  • A.a is queried; the type initializer is already activated (but no assignment has yet occurred), so the field (not yet assigned) is read as 0
  • 0 + 1 is 1, which is assigned to B.b <===========================
  • we now exit the B cctor and go back to the A cctor
  • 1 + 1 is 2, which is assigned to A.a <===========================
  • we now exit the A cctor
  • 2 is returned (WriteLine) for A.a
  • we query (on WriteLine) B.b; the cctor has already fired so we see 1
伴随着你 2024-09-07 18:47:38

马克是对的。我只想在他的回答中补充一点,规范的第 10.5.5.1 节回答了您的问题,其中指出:

静态字段变量初始值设定项
一个类对应一个序列
中执行的分配
它们出现的文本顺序
类声明。如果有静电
类中存在构造函数,
静态字段的执行
初始化器立即发生在
执行该静态构造函数。
否则,静态字段
初始化程序的执行时间为
依赖实施的时间之前
第一次使用静态字段
那个班级。

请注意最后一点。该规范继续引用您的确切示例,作为规范允许任一订购的情况;所有规范保证字段初始值设定项是在静态构造函数运行之前按文本顺序完成的。 它不保证一种类型的字段在另一种类型的字段之前或之后初始化。

例如,允许 jit 编译器说“嘿,我看到类型 A 和 B 用于第一次使用即将被抖动的方法时,让我花点时间确保这些类型已加载。”此时允许 jitter 执行字段初始化程序,并且可以自行决定选择先执行 A 还是先执行 B。

简而言之:(1) 你不能依赖这种行为;它是实现定义的,并且 (2) 规范回答了您的确切问题; 当您对语言语义有疑问时,请考虑阅读规范

Marc is correct. I would just add to his answer that your question is answered by section 10.5.5.1 of the specification, which states:

The static field variable initializers
of a class correspond to a sequence of
assignments that are executed in the
textual order in which they appear in
the class declaration. If a static
constructor exists in the class,
execution of the static field
initializers occurs immediately prior
to executing that static constructor.
Otherwise, the static field
initializers are executed at an
implementation-dependent time prior to
the first use of a static field of
that class.

Notice that last point. The spec goes on to quote your exact example as a case where either ordering is permitted by the specification; all the spec guarantees is that the field initializers are done in textual order before the static constructors run. It does not guarantee that fields of one type are initialized before or after fields of another type.

For example, the jit compiler is permitted to say "hey, I see that types A and B are used for the first time in this method that is about to be jitted, let me take a moment to make sure those types are loaded." The jitter is permitted to execute the field initializers at this time, and can choose to do A first or B first at its discretion.

In short: (1) you cannot rely on this behaviour; it is implementation-defined, and (2) the specification answers your exact question; consider reading the specification when you have a question about language semantics.

蓝戈者 2024-09-07 18:47:38

它与访问静态属性的顺序有关。
第一个计算的是 Aa 当计算 Aa 时,Bb 被初始化。由于对a的实际赋值尚未完成,a的值仍为0,因此Bb变为1。
Bb初始化后,可以将值赋给Aa,即1+1,即2

It has to do with the order in which you access the static properties.
The first evaluated is A.a. When evaluating A.a, B.b gets initialized. Since the actual assignment to a is not finished, the value of a remains 0, thus B.b becomes 1.
After B.b is initialized, the value can be assigned to A.a, that is 1+1, thus 2

鸩远一方 2024-09-07 18:47:38

第一个加载的类型恰好是 A。因此,该类型被加载,并且它的静态成员a 获得默认值零。之后,A 的静态构造函数被调用。该构造函数引用类型 B,因此 B 也会被加载,并且它的静态构造函数也会被调用。反过来,该构造函数引用类型 A,但 A 已加载,因此这里什么也没有发生,并且 b 的值为零( a 的当前值)加一,即为一。之后,B 的静态构造函数返回,并计算a 的值。

The first type to load happens to be A. So the type gets loaded, and it's static member a gets it's default value of zero. After that, A's static constructor get called. That constructor references type B, so B also gets loaded and it's static constructor gets called. That constructor, in turn, references type A, but A is already loaded, so nothing happens here, and b gets it's value of zero (current value of a) plus one, which is one. After that, static constructor of B returns, and a's value is calculated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文