来看案例:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PropertyTest : MonoBehaviour { // Start is called before the first frame update void Start() { transform.position = new Vector3(0, 0, 0); // 为什么通过这个语句可以进行赋值操作呢? // 鼠标移动到 position 上面可以看到 {get;set;} // 说明我们可以从中获取数据,也可以设置数据 // 另外一个例子是:Time.deltaTime 增量时间(代表时间修正到真实时间) // 如果鼠标移动到说明可以看到 {get;} // 这表示只能获取,不能设置 // 所以我们不能赋值,即不能写成 Time.deltaTime = 5; 这样 } // Update is called once per frame void Update() { } } 如何定义我们自己的 property假设我们设置一个 bool 变量监控游戏是否结束:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PropertyTest : MonoBehaviour { public bool isGameOver; // 指示游戏是否结束 // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } public void GameOver() // 当玩家死亡的时候触发调用该方法 { isGameOver = true; // 游戏结束变为 true 的时候,游戏 UI 显示 GAME OVER } }其实我们可以直接在 property 的内部进行相应的操作:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PropertyTest : MonoBehaviour { private bool isGameOver; // 指示游戏是否结束 // 设置为 private 后仅有该脚本本身可以访问该变量 // 我们希望该变量变为只读 public bool IsGameOver // property 的声明,使用 pascal casing 命名方式 { get { return isGameOver; // 读取对应数值 } set { isGameOver = value; // 赋值操作,这里 value 的数据类型需要和目标一致,这里为 bool } } // Start is called before the first frame update void Start() { isGameOver = false; // 游戏开始,初始化为 false } // Update is called once per frame void Update() { } }当我们设置了 property 的声明后,在下面的语句中输入 isGameOver 后,鼠标移动到上面就可以看到 {get; set; },如果仅仅设置了 get,那会显示 {get; }。
然后我们把修改 UI 的链接内置到 property 中:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PropertyTest : MonoBehaviour { private bool isGameOver; // 指示游戏是否结束 // 设置为 private 后仅有该脚本本身可以访问该变量 // 我们希望该变量变为只读 public bool IsGameOver // property 的修饰符,使用 pascal casing 命名方式 { get { return isGameOver; // 读取对应数值 } set { if (value == true) { Debug.Log("GAME OVER"); // 假设链接到 UI 上显示 GAME OVER } isGameOver = value; // 赋值操作,这里 value 的数据类型需要和目标一致,这里为 bool } } // Start is called before the first frame update void Start() { IsGameOver = false; // 游戏开始,初始化为 false } // Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.Space)) // 假设按下空格键表示玩家死亡 { IsGameOver = true; // 触发游戏结束的指示 } } }特别注意:这里在脚本里输入 isGameOver 后有两个选择,一个是 F (isGameOver),另外一个是 P (IsGameOver),我们想要调用 get 和 set,就必须使用 P 的这个 IsGameOver。
举例:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PropertyTest : MonoBehaviour { public bool IsGameOver { get; set; } // 设为 auto property // Start is called before the first frame update void Start() { IsGameOver = false; // 这里 auto property 可以当作普通的变量使用 // 但是和一般的 property 的区别在于,不能在里面添加额外的代码 } // Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.Space)) // 假设按下空格键表示玩家死亡 { IsGameOver = true; // 触发游戏结束的指示 } } }如果我们想要 IsGameOver 仅限至于本脚本可以更改,外部脚本只能访问而不能修改其值,在 set 前面添加 private 即可:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PropertyTest : MonoBehaviour { public bool IsGameOver { get; private set; } // 设为 auto property // Start is called before the first frame update void Start() { IsGameOver = false; // 这里 auto property 可以当作普通的变量使用 // 但是和一般的 property 的区别在于,不能在里面添加额外的代码 } // Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.Space)) // 假设按下空格键表示玩家死亡 { IsGameOver = true; // 触发游戏结束的指示 } } }根据需要,如果需要子类可以访问修改,那设置成 protected set 即可。
总结一下,property 是让我们拥有了一个可变性更强的,更智能的“变量”。
但是 property 有个缺点,就是无法在 inspector 中查看(除非进入 debug 模式)。