boxmoe_header_banner_img

Hello! 欢迎来到盒子萌!

文章导读

[C#][Unity]继承MonoBehaviour的泛型单例


avatar
Ib_Mccf 2025年10月26日 36

单例模式是一种设计模式,它确保一个类在整个应用程序中只有一个实例存在,并提供一个全局的访问点来获取这个唯一的实例。

using UnityEngine;

public class GameManager : MonoBehaviour
{
    // 1. 提供一个静态的、全局唯一的实例
    public static GameManager Instance { get; private set; }

    // 2. 在 Awake 中处理实例化的逻辑
    private void Awake()
    {
        // 检查是否已经有实例存在
        if (Instance != null && Instance != this)
        {
            // 如果有,说明这是个重复的实例,销毁自己
            Destroy(this.gameObject);
        }
        else
        {
            // 如果没有,将自己赋值给这个静态实例
            Instance = this;
        }
    }

    // ... 其他游戏管理逻辑 ...
    public void StartGame()
    {
        Debug.Log("游戏开始!");
    }
}

泛型(在 C# 中用 <T> 表示)允许你编写一个可以与任何数据类型一起工作的类或方法,就像一个“类型模板”。

using UnityEngine;

/// <summary>
/// 一个支持懒加载(自动创建)的泛型 MonoBehaviour 单例基类。
/// 它会优先寻找场景中已存在的实例,如果找不到,则会自动创建一个。
/// </summary>
/// <typeparam name="T">必须是一个 MonoBehaviour 组件</typeparam>
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    // 使用 lock 对象来处理多线程情况(虽然在 Unity 主线程中不常见,但这是个好习惯)
    private static readonly object _lock = new object();
    private static T _instance;

    public static T Instance
    {
        get
        {
            // 在访问实例时加锁,防止多线程问题
            lock (_lock)
            {
                // 如果实例已经存在,直接返回
                if (_instance != null)
                    return _instance;

                // 1. 首先,尝试在场景中查找已经存在的实例
                // 这可以处理“先访问Instance后执行Awake”的竞争问题
                _instance = FindObjectOfType<T>();

                // 2. 如果场景中仍然没有找到
                if (_instance == null)
                {
                    // 3. 动态创建一个新的 GameObject 并挂载组件
                    GameObject singletonObject = new GameObject();
                    _instance = singletonObject.AddComponent<T>();
                    singletonObject.name = $"{typeof(T).Name} (Singleton)";
                    
                    // 可选:如果你希望这个单例跨场景存在
                    // DontDestroyOnLoad(singletonObject);
                }

                return _instance;
            }
        }
    }

    protected virtual void Awake()
    {
        // 处理场景中已经放置了该单例的情况
        if (_instance == null)
        {
            // 如果静态实例为空,将自己赋值给它
            _instance = this as T;
            
            // 可选:如果你希望这个单例跨场景存在
            // DontDestroyOnLoad(this.gameObject);
        }
        else if (_instance != this)
        {
            // 如果静态实例已存在且不是自己,说明自己是重复的,销毁自己
            Debug.LogWarning($"场景中存在重复的单例: {typeof(T).Name},已销毁后来的。");
            Destroy(gameObject);
        }
    }

    protected virtual void OnDestroy()
    {
        if (_instance == this)
        {
            _instance = null;
        }
    }
}



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码