注意:在此仅提及 Unity 开发中会用到的一些功能和特性,对于不适合在 Unity 中使用的内容会忽略。
C# 8 对应 Unity 版本:
- Unity 2020.3 —— C# 8
但是部分新内容还不在该版本 Unity 中被支持,下面筛选了一些比较实用的内容。
C# 8 新增功能和语法:
- Using 声明
- 静态本地函数
- Null 合并赋值
- 解构函数 Deconstruct
- 模式匹配增强功能
一、Using 声明
Using 声明是对 using 语法的简写,当函数执行完毕时会调用对象的 Dispose 方法来释放对象。
public class Lesson10 : MonoBehaviour
{
void Start() {
using StreamWriter s2 = new StreamWriter("文件路径");
// 对该对象进行逻辑操作
s2.Write(5);
s2.Flush();
s2.Close();
// 利用这个写法 就会在上层语句块执行结束时释放该对象
}
}
注意:在使用 using 语法时,声明的对象必须继承 System.IDisposable 接口:
public class TestUsing : IDisposable
{
public void Dispose() { }
}
public class Lesson10 : MonoBehaviour
{
void Start() {
using TestUsing t = new TestUsing();
}
}
因为必须具备 Dispose 方法,所以当声明没有继承该接口的对象时会报错.
二、静态本地函数
静态本地函数就是在本地函数前方加入静态关键字。
作用:让本地函数不能够使用访问封闭范围内(也就是上层方法中)的任何变量,让本地函数只能处理逻辑,避免让它通过直接改变上层变量来处理逻辑造成逻辑混乱。
public int TestTst(int i) {
bool b = false;
i += 10;
Calc(ref i, ref b); // 执行静态本地函数
return i;
// 静态本地函数
static void Calc(ref int i, ref bool b) {
i += 10;
b = true;
}
}
三、Null 合并赋值
空合并赋值是 C# 8.0 新加的一个运算符 ??=
,类似复合运算符:
左边值 ??= 右边值
当左侧为空时才会把右侧值赋值给变量。
举例:
string str = null;
str ??= "4565";
print(str); // "4565"
// 注意:由于左侧为空才会讲右侧赋值给变量,所以不为空的变量不会改变
str ??= "1111";
print(str); // "4565"
四、解构函数 Deconstruct
我们可以在自定义类当中声明解构函数,这样我们可以将该自定义类对象利用元组的写法对其进行变量的获取。
语法:在类的内部声明函数:
public void Deconstruct(out 变量类型 变量名, out 变量类型 变量名.....)
特点:一个类中可以有多个 Deconstruct,但是参数数量不能相同。
public class Person
{
public string name;
public bool sex;
public string number;
public string email;
// 三个解构函数
public void Deconstruct(out string n, out bool sex) {
n = name;
sex = this.sex;
}
public void Deconstruct(out string n, out bool sex, out string number) {
n = name;
sex = this.sex;
number = this.number;
}
public void Deconstruct(out string n, out bool sex, out string number, out string email) {
n = name;
sex = this.sex;
number = this.number;
email = this.email;
}
}
public class Lesson10 : MonoBehaviour
{
void Start() {
// 初始化并赋值
Person p = new Person();
p.name = "xxx";
p.sex = false;
p.number = "123123123123";
p.email = "xxxxxxxx@163.com";
// 对该对象利用元组将其具体的变量值解构出来
// 相当于把不同的成员变量拆分到不同的临时变量中
(string name, bool sex) = p;
print(name); // "xxx"
print(sex); // "false"
string str3;
(_, _, str3) = p;
print(str3); // "123123123123"
}
}
解构函数也可以简写成:
public void Deconstruct(out string n, out bool sex) => (n, sex) = (this.name, this.sex);
public void Deconstruct(out string n, out bool sex, out string number) => (n, sex, number) = (this.name, this.sex, this.number);
public void Deconstruct(out string n, out bool sex, out string number, out string email) => (n, sex, number, email) = (this.name, this.sex, this.number, this.email);
五、模式匹配增强功能
C# 7 中模式匹配已经有常量模式、类型模式和 var 模式三种,在 C# 8 中新加入了如下几种模式:
- switch 表达式
- 属性模式
- 元组模式
- 位置模式
(一)switch 表达式
对于如下枚举:
public enum PosType
{
Top_Left,
Top_Right,
Bottom_Left,
Bottom_Right,
}
当需要写一个函数获取对应位置时,使用 switch 写法如下:
public Vector2 GetPos(PosType type) {
switch (type) {
case PosType.Top_Left:
return new Vector2(0, 0);
case PosType.Top_Right:
return new Vector2(1, 0);
case PosType.Bottom_Left:
return new Vector2(0, 1);
case PosType.Bottom_Right:
return new Vector2(1, 1);
default:
return new Vector2(0, 0);
}
}
switch 表达式是对有返回值的 switch 语句的缩写:
- 用
=>
表达式符号代替case:
组合 - 用
_
弃元符号代替default:
它的使用限制,主要是用于 switch 语句当中只有一句代码用于返回值时使用:
public Vector2 GetPos(PosType type) => type switch {
PosType.Top_Left => new Vector2(0, 0),
PosType.Top_Right => new Vector2(1, 0),
PosType.Bottom_Left => new Vector2(0, 1),
PosType.Bottom_Right => new Vector2(1, 1),
_ => new Vector2(0, 0)
};
(二)属性模式
即在常量模式的基础上判断对象上各属性。
用法:变量 is {属性:值, 属性:值}
。
对于如下折扣类:
public class DiscountInfo
{
public string discount;
public bool isDiscount;
public DiscountInfo(string discount, bool isDiscount) {
this.discount = discount;
this.isDiscount = isDiscount;
}
public void Deconstruct(out string dis, out bool isDis) {
dis = this.discount;
isDis = this.isDiscount;
}
}
如果需要判断其具体信息,需要获取其两个成员变量的值进行判断:
DiscountInfo info = new DiscountInfo("5折", true);
if( info.discount == "6折" && info.isDiscount)
print("信息相同");
使用属性模式可以快捷判断:
if (info is { discount: "6折", isDiscount: true })
print("信息相同");
结合 switch 表达式:
public float GetMoney(DiscountInfo info, float money) => info switch {
// 属性模式结合 switch 表达式判断 n 个条件是否满足
{ discount: "5折", isDiscount: true } => money * .5f,
{ discount: "6折", isDiscount: true } => money * .6f,
{ discount: "7折", isDiscount: true } => money * .7f,
_ => money
};
(三)元组模式
元组模式可以不需要声明数据结构类,可以直接利用元组进行判断:
int ii = 10;
bool bb = true;
if ((ii, bb) is (11, true)) {
print("元组的值相同");
}
public float GetMoney(string discount, bool isDiscount, float money) => (discount, isDiscount) switch {
("5折", true) => money * .5f,
("6折", true) => money * .6f,
("7折", true) => money * .7f,
_ => money
};
(四)位置模式
如果自定义类中实现了解构函数,那么可以直接用对应类对象与元组进行 is 判断:
if (info is ("5折", true)) {
print("位置模式 满足条件");
}
同时还可以配合 when 关键字进行逻辑处理:
public float GetMoney2(DiscountInfo info, float money) => info switch {
("5折", true) when money > 100 => money * .5f,
("6折", true) => money * .6f,
("7折", true) => money * .7f,
_ => money
};