来看案例:
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()
{
}
}
假设我们设置一个 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 模式)。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PropertyTest : MonoBehaviour
{
public int Speed { get; private set; } // 速度,对于别的脚本只读
private string _playerName; // 名字
public string PlayerName
{
get
{
Debug.Log("get method called");
return _playerName;
}
set
{
Debug.Log("set method called");
_playerName = value;
}
}
// Start is called before the first frame update
void Start()
{
Speed = 16;
Speed += 10;
Debug.Log("Speed: " + Speed);
PlayerName = "Mike";
PlayerName += "s";
Debug.Log("Player name: " + PlayerName);
}
// Update is called once per frame
void Update()
{
}
}