C#不使用static跨类访问变量报CS0120错误解决方案
问题原因
你遇到的CS0120报错核心原因是:非静态的字段、方法属于类的具体实例(对象),不能直接通过类名调用。
你之前用static能跑是因为静态成员是类级别的,不需要实例就能直接访问,但全局滥用静态确实会导致代码耦合度高、生命周期不可控、场景切换数据残留等问题,不符合面向对象的编码规范。
你写的generalManager.getEggs()是直接用类名调用非静态方法,编译器无法定位你要访问的是哪个generalManager对象里的eggs数据,才会抛出这个错误。
正确实现方案(Unity环境下,无需static)
Unity中跨MonoBehaviour类访问成员的核心逻辑是:先拿到目标类挂载在场景物体上的实例引用,再通过引用调用getter/setter操作变量。
第一步:修正GeneralManager脚本
注意Unity要求C#脚本文件名必须和类名完全一致,所以脚本要命名为GeneralManager.cs:
using UnityEngine; public class GeneralManager : MonoBehaviour { // 私有字段加[SerializeField]可在Inspector面板编辑,比public字段更安全 [SerializeField] private float _eggs; // C#标准属性实现get/set,替代手写getEggs/setEggs方法 public float Eggs { get => _eggs; set => _eggs = value; } }
第二步:在GameManager中获取实例并访问
两种最常用的获取引用方式,选一种即可:
方式1:Inspector拖拽赋值(推荐,耦合最低)
脚本写好后,在Inspector面板把挂载了GeneralManager脚本的场景物体,拖到GameManager组件的对应字段上完成赋值,运行时就可以直接访问:
using UnityEngine; public class GameManager : MonoBehaviour { // 拖拽赋值后,这个字段就持有了GeneralManager的实例引用 [SerializeField] private GeneralManager _generalManager; private void Start() { // 取值 float currentEggCount = _generalManager.Eggs; Debug.Log($"当前鸡蛋数量:{currentEggCount}"); // 赋值 _generalManager.Eggs = 15f; } }
方式2:运行时动态获取
如果不想手动拖拽,可以在生命周期函数里动态查找获取实例:
using UnityEngine; public class GameManager : MonoBehaviour { private GeneralManager _generalManager; private void Awake() { // 如果GeneralManager和GameManager挂在同一个GameObject上,用这行 _generalManager = GetComponent<GeneralManager>(); // 如果GeneralManager挂在场景中名为"ManagerRoot"的独立GameObject上,用这行 // _generalManager = GameObject.Find("ManagerRoot").GetComponent<GeneralManager>(); } private void Start() { // 判空避免空引用报错 if (_generalManager == null) { Debug.LogError("未找到GeneralManager实例,请检查脚本挂载配置"); return; } // 取值 float eggs = _generalManager.Eggs; // 赋值 _generalManager.Eggs = 20f; } }
注意事项
- 不要图省事把所有Manager都做成全局单例,这种用法本质和滥用static区别不大,能通过传引用解决的场景优先用引用,代码可维护性更高。
- 面向对象的核心规则是:类是创建对象的模板,非静态成员存储在具体实例中,必须拿到实例引用才能访问,直接通过类名只能访问静态成员。
内容的提问来源于stack exchange,提问作者Pierre Marsaa
相关产品推荐
相关产品推荐

