天了噜!定义static字段还有顺序要求?

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了天了噜!定义static字段还有顺序要求?相关的知识,希望对你有一定的参考价值。

前言

前段时间,发现一个bug,代码结构类似下面的示例。你能说出这段代码的正确返回结果吗?

class Program

    private static int a1 = a2;
    private static int a2 = Init();

    private static int Init()
    
        return 123;
    

    static void Main(string[] args)
    
        Console.WriteLine($@"a1 a2");
    

答案是0 123!

如果改成这样则返回123 123

private static int a2 = Init();
private static int a1 = a2;

定义static字段还有顺序要求?

微软官方文档[1]明明是这样说的:

在首次访问静态成员之前以及在调用构造函数(如果有)之前,会初始化静态成员。

不是应该a2被访问之前会初始化吗?

原因

通过C#代码看不出问题,我们看看IL代码[2]实现:

  • ldsfld 将静态字段的值推送到计算堆栈上

  • stsfld 用来自计算堆栈的值替换静态字段的值

原来,静态字段的初始化,是在所在类的静态构造函数中,按照定义的顺序依次完成的。

由于a1和a2是在同一个类里定义的,为a1赋值时a2还没有值,所以使用的是int类型默认值。

解决方法

为了避免这个问题,最好不使用同一个类里的静态字段用于初始化,类似这样:

private static int a1 = OtherClass.a2;

如果就是要这样用,可以改成这样的写法:

private static int b1 = b2;
private static int b2 => Init();

通过IL代码可以看到:

b2被转换成get属性,因此不用初始化。

结论

细节是魔鬼!原来定义static字段还真有顺序要求!

如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“,记住我!

参考资料

[1]

微软官方文档: https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members#static-members

[2]

IL代码: C#源代码会被编译为IL代码,运行时将IL转为机器能识别的机器码

以上是关于天了噜!定义static字段还有顺序要求?的主要内容,如果未能解决你的问题,请参考以下文章

天了噜,原来有效的复盘要这样做,微妙

天了噜,原来有效的复盘要这样做,微妙

天了噜,原来有效的复盘要这样做,微妙

天了噜!抽奖抽到一台价值658元的kindle电子阅读器!与大家分享喜悦!

天了噜!程序媛离职,为宣泄不满rm-f×删库,客运总站瘫痪 6 个小时

Java 8 停止维护,Java 9 难产,IDEA 2018 发布,还有……