静态构造函数和BeforeFieldInit?如果该类型没有静态构造函数,则字段初始值设定项将在使用该类型之前执行-或者在运行时突发奇想之前的任何时间为什么这段代码:voidMain(){"--------start----“。倾倒();Test.EchoAndReturn("你好");"--------结束--------".Dump();}classTest{publicstaticstringx=EchoAndReturn("a");公共静态字符串y=EchoAndReturn("b");publicstaticstringEchoAndReturn(strings){Console.WriteLine(s);返回s;}}输出:-------start--------abHello--------end--------这段代码:voidMain(){"-------开始-------".Dump();变种测试=Test.x;"--------结束--------".Dump();}yieldab------start------------end--------a和b的顺序可以理解。但是为什么处理静态方法不同于静态字段。我的意思是为什么静态方法和静态字段的起始行和结束行在不同的地方?我的意思是——在这两种情况下,他都必须初始化这些字段……为什么?(我知道我可以添加一个静态ctor,所以它是一样的——但我问的是这个特殊情况。)(psDump()就像console.write)释放JIT的行为(从4.0IIRC开始)没有运行静态初始值设定项,除非您调用该方法接触静态字段。这可能意味着静态字段未初始化。如果我在调试器之外的版本中运行你的第一个代码,我得到:------start--------Hello--------end-------如果我运行它附加调试器(发布)或调试版本(有或没有调试器),我得到:------start--------abHello-------end-------到目前为止很有趣。为什么会得到:ab------start--------------end--------看起来在这种情况下,每个方法的JIT基本上是负责的运行静态构造函数。您可以通过添加:if(NeverTrue()){//返回false的方法"-------start--------".Dump();vartest=Test.x;"-------结束--------".Dump();}将打印(即使在没有调试器的情况下发布)ab因此访问字段的可能性是关键。如果我们将Test.x更改为对不访问该字段的方法的调用(并删除NeverTrue()东西),那么我们不会得到任何输出。因此:在某些版本的CLI中,静态初始化程序的执行可能会延迟到包含对任何字段的提及的方法的JIT步骤(它不会检查该字段是否具有初始化程序)。我们甚至可以在不运行静态初始化器的情况下创建对象实例,只要我们不接触静态字段:}串一个;与:“--------开始-------”.Dump();新测试();"--------结束--------".Dump();仅打印(发布,无调试器):-------开始-------------结束--------然而!我们不应该基于这个时间构建任何东西:无法保证何时调用静态构造函数,因此对于程序来说,它就像C++中的未定义行为。没有人应该依赖静态构造函数调用的顺序。例如,如果您在发布时编译您的程序,您将看到静态构造函数在两种情况下都被调用。这是使用.NET4.0如果类型没有静态构造函数但已初始化静态字段,则编译器会创建一个类型构造函数并将初始化放在那里。类测试{publicstaticstringx=EchoAndReturn("a");公共静态字符串y=EchoAndReturn("b");公共静态字符串EchoAndReturn(strings){Console.WriteLine(s);返回s;}}导致以下IL(只是cctor部分).methodprivatehidebysigspecialnamertspecialnamestaticvoid.cctor()cilmanaged{//Codesize31(0x1f).maxstack8IL_0000:ldstr"a"IL_0005:callstringConsoleApplication1.Test::EchoAndReturn(字符串)IL_000a:stsfld字符串ConsoleApplication1.Test::xIL_000f:ldstr“b”IL_0014:调用字??符串ConsoleApplication1.Test::EchoAndReturn(字符串)IL_0019:stsfld字符串ConsoleApplication1.Test::yIL_001e:ret}//方法结束Test::.cctor此外,根据C#的CLR,JIT编译器会预先检查每个方法,哪些类型具有静态构造函数。如果尚未调用静态构造函数,则JIT编译器将调用它。这将解释两个代码片段之间的区别。当即时(JIT)编译器编译方法时,它会查看代码中引用了哪些类型。如果任何类型定义了类型构造函数,JIT编译器将检查该类型的类型构造函数是否已为此AppDomain执行。如果从未执行过构造函数,那么JIT编译器会发出一个调用,以将类型构造函数转换为JIT编译器发出的本机代码。@Comment如果将字段初始值设定项移动到用户定义的类型构造函数中,编译器也会将您在类级别初始化的另一个字段移动到类型构造函数中。静态测试(){y=EchoAndReturn(“b”);}结果和上面的IL是一样的。所以你自己的类型构造函数和编译器生成的构造函数之间基本上没有区别(反正只能有一个)。以上就是C#学习教程:静态构造函数和BeforeFieldInit?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
