Unity 中区别,public 和 [SerializeField]
在 Unity 中,public 和 [SerializeField] 都用于在 Inspector 中显示字段,但它们的核心区别在于访问权限和封装性。
核心区别
| 特性 | public | [SerializeField] |
|---|---|---|
| Inspector 可见性 | ✅ 可见 | ✅ 可见 |
| 外部访问权限 | ✅ 任何类都可访问 | ❌ 只有本类可访问 |
| 封装性 | ❌ 破坏封装 | ✅ 保持封装 |
| 使用场景 | 需要外部访问 | 仅需 Inspector 编辑 |
详细说明
public 字段
public class Player : MonoBehaviour { public float speed = 5f; // 其他类可以直接修改 }
- 任何其他类都可以通过
player.speed访问和修改 - 破坏了面向对象的封装原则
- 可能导致不可预期的修改
[SerializeField] 私有字段
public class Player : MonoBehaviour { [SerializeField] private float speed = 5f; // 只有本类可修改 }
- 保持私有性,其他类无法直接访问
- 仍然在 Inspector 中可见可编辑
- 遵循封装原则
推荐实践
推荐使用 [SerializeField] 的场景
public class Player : MonoBehaviour { [SerializeField] private float moveSpeed = 5f; [SerializeField] private GameObject bulletPrefab; [SerializeField] private int maxHealth = 100; // 如果需要外部访问,提供公共属性 public float MoveSpeed => moveSpeed; public int MaxHealth => maxHealth; }
应该使用 public 的场景
public class GameManager : MonoBehaviour { // 其他类需要频繁修改 public static GameManager Instance; // 需要被其他系统直接调用 public void StartGame() { } }
进阶技巧
使用属性封装
public class Player : MonoBehaviour { [SerializeField] private int health = 100; public int Health { get => health; set { health = Mathf.Clamp(value, 0, maxHealth); OnHealthChanged?.Invoke(health); } } public event System.Action<int> OnHealthChanged; }
使用 [SerializeField] 的扩展
public class Weapon : MonoBehaviour { [SerializeField] private int damage = 10; [SerializeField] [Range(0, 100)] private int accuracy = 80; [SerializeField] [Tooltip("子弹速度,单位:米/秒")] private float bulletSpeed = 100f; [SerializeField] [HideInInspector] private int serialNumber; // 序列号不在Inspector显示 }
总结
- 优先使用
[SerializeField] private:保持封装性,只暴露必要的 Inspector 接口 - 仅在需要外部访问时使用
public:如静态单例、公共方法等 - 考虑使用属性:在需要额外逻辑(验证、触发事件)时替代直接暴露字段
- 团队协作:建议制定统一的编码规范,明确何时使用哪种方式
这样做既能保持代码的健壮性,又能充分利用 Unity Inspector 的可视化编辑优势。
浙公网安备 33010602011771号