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

C#与Unity单例未实例化问题:为何Unity可用控制台程序不行?

问题描述

参考Unity教程实现了GameManager单例,该实现在第一个Unity小项目中可正常使用,但第二次使用时实例创建失败。随后在C#控制台程序中编写测试代码,调用Program.Instance时无法正常工作,需明确问题原因及Unity项目中能运行的缘由。

Unity单例示例代码

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }
    int scoreCount=0;
    //...
}
//使用实例的代码:
class Player : MonoBehaviour
{
    //...
    GameManager.Instance.scoreCount++;
    //...
}

控制台测试代码

using System;

namespace ConsoleApp1
{
    class classiii
    {
        static void Main(string[] args)
        {
            string input = Console.ReadLine();
            int result = Int32.Parse(input);
            Console.WriteLine(Program.Instance.A(result));
            Console.ReadLine();
        }
    }
    class Program
    {
        public static Program Instance { get; private set; }

        int firstNum = 5;
        public int A(int tmp)
        {
            return firstNum + tmp;
        }
    }
}
问题原因分析
  • Unity项目能运行的核心原因:
    Unity的MonoBehaviour对象由引擎自动实例化,当场景中存在挂载GameManager脚本的GameObject时,引擎会在场景加载时创建该脚本实例。你参考的教程里大概率包含了Awake方法的赋值逻辑(你贴的代码里没写),比如:

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
    

    这段代码会在Unity实例化GameManager时给静态Instance属性赋值,所以能正常调用。

  • 第二次Unity项目实例创建失败的原因:
    要么是场景中没有挂载GameManager的GameObject,引擎无法自动实例化对象,导致Instance一直为null;要么是场景中存在多个挂载GameManager的对象,后创建的实例被销毁,但前一个实例的赋值逻辑出现问题(比如未添加DontDestroyOnLoad导致场景切换时实例被销毁)。

  • 控制台程序无法运行的原因:
    纯C#控制台环境没有Unity引擎的自动实例化机制,Program.Instance作为静态属性,你没有在任何地方给它赋值,默认值为null。调用Program.Instance.A(result)时会触发NullReferenceException,因为你在访问一个空对象的方法。

修复方案

Unity单例的正确实现(补全缺失逻辑)

确保GameManager包含完整的单例初始化逻辑,避免实例为null或多实例问题:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }
    int scoreCount = 0;

    private void Awake()
    {
        // 单例核心逻辑
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject); // 跨场景保留实例
        }
        else
        {
            Destroy(gameObject); // 销毁重复实例
        }
    }

    // 封装分数修改逻辑,避免直接访问私有字段
    public void AddScore()
    {
        scoreCount++;
    }
}

使用时确保场景中仅存在一个挂载GameManager的GameObject,或通过代码动态创建实例(若场景中没有)。

控制台程序的单例实现

需要手动初始化静态Instance属性,常见两种实现方式:

  1. 饿汉式(程序启动时初始化):
class Program
{
    // 静态初始化,程序启动时自动创建实例
    public static Program Instance { get; private set; } = new Program();

    int firstNum = 5;
    public int A(int tmp)
    {
        return firstNum + tmp;
    }
}
  1. 懒汉式(第一次访问时初始化):
class Program
{
    private static Program _instance;
    private static readonly object _lock = new object(); // 线程安全锁

    public static Program Instance
    {
        get
        {
            lock (_lock)
            {
                if (_instance == null)
                {
                    _instance = new Program();
                }
                return _instance;
            }
        }
    }

    int firstNum = 5;
    public int A(int tmp)
    {
        return firstNum + tmp;
    }
}

两种方式都能保证调用Program.Instance.A(result)时正常获取实例并执行方法。

内容的提问来源于stack exchange,提问作者yuan qi peng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 07:48:46