Using Static Constructor (Jon Skeet Brainteaser)
作为一个相对新手,我尽可能多地阅读某个特定主题,尽可能多地测试/编写代码。我在看乔恩的一个脑筋急转弯(问题2),我的输出与答案不同。这使得我来到这里,询问最近的版本中是否发生了变化,并了解其他人从代码中得到了什么输出。
问题是,"将显示什么,为什么,以及你有多自信?"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| using System;
class Foo
{
static Foo ()
{
Console .WriteLine ("Foo");
}
}
class Bar
{
static int i = Init ();
static int Init ()
{
Console .WriteLine("Bar");
return 0;
}
}
class Test
{
static void Main ()
{
Foo f = new Foo ();
Bar b = new Bar ();
}
} |
什么,如果有的话,会导致我们得到两个不同的答案?
- 您在问"最近版本的Visual Studio是否发生了变化"。你真正要问的是.NET框架的新版本是否有任何变化。而且,真的没有什么大的改变会从一个版本到另一个版本,因为这将是一个重大的突破性的改变。
- 复制。有趣。
- 嗯,你得到的答案是什么?
- 今天早些时候我刚在乔恩的网站上读到这个。@jprete是正确的,这是因为foo类中的静态构造函数。yoda.arachsys.com/csharp/beforefieldinit.html
现在在调试器之外的释放模式下尝试;-p
我使用/不使用调试器得到不同的结果。调试程序会扰乱许多细微的细微差别/优化,所以我只能猜测这是调试程序最重要的时候之一。这使得调试更加困难;-p
- 这正是我所缺少的。
- 我在释放模式下得到"foo",在调试模式下得到"foo"和"bar"。从原始编程语言的角度来看,"foo"和"bar"都不应该按顺序显示吗?
Jon自己的答案页面对此进行了讨论。我不是一个C家伙,但看起来系统在何时调用静态foo代码(因此写"foo")上只有一个选择,但是它在本质上有无限的自由来决定何时初始化Bar.i(它将写"bar"),所以它可以在类被加载时,或者在它第一次被使用时,或者根本没有发生。
它在调试模式下打印foo,bar,在释放模式下打印foo。所以现在所发生的是发布代码被优化,优化会导致首先调用BAR——但是不能保证总是这样。
- 为什么优化会导致首先调用bar。这里的规则是什么?
- 我必须检查一下,但是如果它是调试器,而不是调试/发布,那么我不会感到惊讶,这会使事情变得不愉快。它经常这样。
- 因为bar没有静态构造函数,所以它可以初始化i的值并提前准备好bar类。这样可以防止以后发生更多的工作。或者,调试器稍后会让BAR初始化。因为foo有构造函数,所以它在第一次创建时总是会被初始化,而bar随时都可以被初始化。
- @我在IDE外运行这两个程序来获得这些结果,所以我不认为调试器是这里的因素。
我想FOO栏会被打印出来。静态类型构造函数将首先在foo中执行,然后在bar类上调用init方法。但我不知道这种行为是否会改变。这很有趣。
只要看看它,如果它除了"foobar"之外还显示其他东西,我会很惊讶的。
出于简单的原因,您首先访问foo,因此它的静态构造函数将运行。在实例化条时后跟静态字段初始值设定项。
很高兴被纠正。