You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity 2017中C#静态变量初始化失败:单例模式异常

Unity 2017 单例模式静态readonly字段初始化异常问题排查与解决

嘿,我来帮你捋捋这个问题——我之前在Unity老版本里也踩过类似的坑!你遇到的这个情况,核心原因其实是Unity的Mono运行时和标准.NET的静态字段初始化行为不一致,尤其在2017这种较早的版本里表现得很明显。

先复盘下你的场景:
你写了一个饿汉式单例,用static readonly修饰了两个静态常量,结果在私有的构造函数里打印时,这两个字段都是默认的0值;但移除readonly修饰符后,就能正常输出预期的数值了。

问题根源

在标准C#程序里,静态字段会按照声明的顺序,在类第一次被访问时完成初始化,之后才会执行类的构造函数。但Unity 2017的Mono运行时对非MonoBehaviour类的static readonly字段有特殊的延迟初始化逻辑——它会把这些字段的赋值操作推迟到实例构造函数执行之后,这就导致你在构造函数里访问时,字段还没被赋值,自然只能拿到默认的0值。

几种可行的解决方案

1. 移除readonly修饰符(你已经验证过的方法)

直接去掉readonly,静态字段会在类加载阶段正常完成初始化,构造函数就能拿到正确的数值:

public class Singleton {
    public static readonly Singleton instance = new Singleton();
    static float FLOAT_VAL = 3.5f;
    static int INT_VAL = 3;
    private Singleton() {
        Debug.Log("FLOAT_VAL = " + FLOAT_VAL);
        Debug.Log("INT_VAL = " + INT_VAL);
    }
}

2. 改用懒加载单例(Unity环境更推荐的写法)

饿汉式单例在Unity里容易遇到初始化时机的问题,懒加载可以更稳妥地控制初始化流程,确保静态字段在实例化前已经完成赋值:

public class Singleton {
    private static Singleton _instance;
    public static float FLOAT_VAL = 3.5f;
    public static int INT_VAL = 3;

    private Singleton() {
        Debug.Log("FLOAT_VAL = " + FLOAT_VAL);
        Debug.Log("INT_VAL = " + INT_VAL);
    }

    public static Singleton Instance {
        get {
            if (_instance == null) {
                _instance = new Singleton();
            }
            return _instance;
        }
    }
}

这种写法不仅能解决当前的初始化问题,还能避免Unity启动时不必要的类实例化开销。

3. 保留readonly,改用静态构造函数赋值

如果你一定要保留readonly的不可变性,可以把字段的初始化逻辑放到静态构造函数里。Unity的Mono运行时会保证静态构造函数在实例构造函数之前执行,这样就能确保字段在构造函数调用前已经完成赋值:

public class Singleton {
    public static readonly Singleton instance;
    public static readonly float FLOAT_VAL;
    public static readonly int INT_VAL;

    static Singleton() {
        // 先初始化静态字段
        FLOAT_VAL = 3.5f;
        INT_VAL = 3;
        // 再实例化单例
        instance = new Singleton();
    }

    private Singleton() {
        Debug.Log("FLOAT_VAL = " + FLOAT_VAL);
        Debug.Log("INT_VAL = " + INT_VAL);
    }
}

总结

Unity的Mono运行时和标准.NET环境存在一些行为差异,尤其是在静态成员的初始化时机上,老版本的表现会更突出。在Unity里编写单例时,尽量适配它的生命周期逻辑,就能避免这类奇怪的初始化问题。

内容的提问来源于stack exchange,提问作者GuardHei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:29:26