CS5L10——CSharp 8 功能和语法
CS5L10——CSharp 8 功能和语法
C# 8 对应的Unity版本
Unity 2020.3 —— C# 8
但是部分新内容还不在该版本Unity中被支持,这里筛选了一些比较实用的内容给大家讲解
本章代码关键字
1 | //不愧是C#,语法糖爆炸多,本章知识不建议看这里的关键字,尤其是模式匹配,你在这里看是看不懂的XD |
C# 8 的新增功能和语法
-
Using
声明 - 静态本地函数
-
Null
合并赋值 - 解构函数
Deconstruct
- 模式匹配增强功能
静态本地函数
知识回顾:在C# 7的新语法中我们学习了本地函数
本地函数知识回顾:
基本概念: 在函数内部声明一个临时函数
注意: 本地函数只能在声明该函数的函数内部使用,本地函数可以使用声明自己的函数中的变量
作用: 方便逻辑的封装
建议: 把本地函数写在主要逻辑的后面,方便代码的查看
新知识点:
静态本地函数就是在本地函数前方加入静态关键字 static
它的作用就是让本地函数不能够使用访问封闭范围内(也就是上层方法中)的任何变量
作用: 让本地函数只能处理逻辑,避免让它通过直接改变上层变量来处理逻辑造成逻辑混乱
1 | void Start() |
using 声明
知识回顾:在数据持久化xml相关知识当中,我们学习了using相关的知识点
1 | using (对象声明) |
举例:
1 | using (StreamWriter stream = new StreamWriter("文件路径")) |
新知识点:
Using
声明就是对 using()
语法的简写,当函数执行完毕时会调用对象的 Dispose
方法,释放对象
1 | void Start() |
注意:在使用****using
语法时,声明的对象必须继承****System.IDisposable
接口,因为必须具备****Dispose
方法,所以当声明没有继承该接口的对象时会报错
1 | using System; |
Null 合并赋值
知识回顾:在C#进阶的特殊语法知识点中我们学习了 ??
空合并操作符
回顾空合并操作符知识点 左边值 ?? 右边值
如果左边值为 null
就返回右边值,否则返回左边值,只要是可以为null
的类型都能用
举例:
1 | string str = null; |
新知识点:
空合并赋值是C# 8 新加的一个运算符 ??=
类似复合运算符,即左边值 ??= 右边值
,当左侧为空时才会把右侧值赋值给变量
举例:
1 | string str = null; |
注意:由于左侧为空才会将右侧赋值给左侧变量,所以不为空的变量不会改变
1 | //str2 = str ?? "234"就等价于下面的代码 |
解构函数 Deconstruct()
知识回顾:我们之前学习过元组的解构,就是可以用单独的变量存储元组的值,相当于把多返回值元组拆分到不同的变量中
举例回顾:
1 | void Start() |
新知识点:解构函数 Deconstruct()
(C# 7就有了)
我们可以在自定义类当中声明解构函数,这样我们可以将该自定义类对象利用元组的写法对其进行变量的获取
语法: 在类的内部申明函数 public void Deconstruct(out 变量类型 变量名, out 变量类型 变量名.....)
特点: 一个类中可以有多个 Deconstruct()
,但是参数数量不能相同
1 | public class Person |
我们可以对该对象利用元组将其具体的变量值解构出来,相当于把不同的成员变量拆分到不同的临时变量中
注意,以上的解构函数声明还可以用lambda
表达式更进一步的简化
1 | public class Person |
模式匹配
模式匹配(Pattern Matching),“模式匹配”是一种测试表达式是否具有特定特征的方法
在编程里指的是,把一个不知道具体数据信息的内容,通过一些固定的语法格式来确定模式数据的具体内容的过程
以前学习过的模式匹配
学习过的模式匹配回顾
-
常量模式
(is 常量)
:用于判断输入值是否等于某个值
1
2
3
4
5
6
7
8
9
10
11//我们目前学习过的模式匹配
//1.常量模式(is 常量):用于判断输入值是否等于某个值
object o = 1.5f;
if (o is 1)
{
print("o是1");
}
if (o is null)
{
print("o是null");
} -
类型模式
(is 类型 变量名
、case 类型 变量名
):用于判断输入值类型,如果类型相同,将输入值提取出来
判断某一个变量是否是某一个类型,如果满足会将该变量存入你申明的变量中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18if (o is int i)
{
print(i);
}
switch (o)
{
case int value:
print("int:" + value);
break;
case float value:
print("float:" + value);
break;
case null:
print("null");
break;
default:
break;
} -
var
模式:用于将输入值放入与输入值相同类型的新变量中,相当于是将变量装入一个和自己类型一样的变量中
1
2
3
4
5
6
7
8
9
10
11
12
13
14int GetInt()
{
return 1;
}
if (o is var v)
{
print(v);
}
//旧写法
int kk = GetInt();
if (kk >= 0 && kk <= 10) { }
//新写法,这里旧省略了kk这个中间变量,这里还省略了类型转换,由编译器直接帮我们判断这个函数返回的是何种类型,并将该过程直接并入表达式内
if (GetInt() is var k && k >= 0 && k <= 10) { }
模式匹配增强功能
-
switch表达式
switch
表达式是对有返回值的switch
语句的缩写,用 =>
表达式符号代替case:
组合,用 _
弃元符号代替default
由于其使用限制,这个表达式主要是用于switch
语句当中只有一句代码用于返回值时使用
语法:1
2
3
4
5
6
7
8函数声明 => 变量 switch
{
常量=>返回值表达式,
常量=>返回值表达式,
常量=>返回值表达式,
....
_ => 返回值表达式,
}举例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41using UnityEngine;
//屏幕的顶角方位类型
public enum PosType
{
Top_Left, //左上角
Top_Right, //右上角
Bottom_Left, //左下角
Bottom_Right, //右下角
}
public class Lesson11 : MonoBehaviour
{
//获取某个屏幕的某个顶角的坐标,旧写法
//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);
// }
//}
//获取某个屏幕的某个顶角的坐标,新写法,可以发现type写到了switch前面,而“case 常量:”都被缩减为了“常量 => ”
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 {属性: 值, 属性: 值}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26using UnityEngine;
public class DiscountInfo
{
public string discount;
public bool isDiscount;
public DiscountInfo(string discount, bool isDiscount)
{
this.discount = discount;
this.isDiscount = isDiscount;
}
}
public class Lesson11 : MonoBehaviour
{
void Start()
{
DiscountInfo info = new DiscountInfo("5折", true);
if (info is { discount: "5折", isDiscount: true })
print("信息相同");
//上面等同于下面这种写法
if (info.discount == "5折" && info.isDiscount == true)
print("信息相同");
}
}它可以结合
switch
表达式使用,结合switch
使用可以通过属性模式判断条件的组合1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31using UnityEngine;
public class DiscountInfo
{
public string discount;
public bool isDiscount;
public DiscountInfo(string discount, bool isDiscount)
{
this.discount = discount;
this.isDiscount = isDiscount;
}
}
public class Lesson11 : MonoBehaviour
{
void Start()
{
DiscountInfo info = new DiscountInfo("5折", true);
print(GetMoney(info, 100)); //输出50
}
public float GetMoney(DiscountInfo info, float money) => info switch
{
//可以利用属性模式,结合switch表达式,判断n个条件满足,较if...else if...else的写法更为简洁
{ discount: "5折", isDiscount: true } => money * .5f,
{ discount: "6折", isDiscount: true } => money * .6f,
{ discount: "7折", isDiscount: true } => money * .7f,
_ => money
};
} -
元组模式
通过刚才学习的属性模式,我们可以在
switch
表达式中判断多个变量同时满足再返回什么
但是它必须是一个数据结构类对象,判断其中的变量
而元组模式可以更简单的完成这样的功能,我们不需要声明数据结构类,可以直接利用元组进行判断基本使用:
1
2
3
4
5
6
7
8
9
10
11
12int ii = 10;
bool bb = true;
if ((ii, bb) is (10, true))
{
print("元组的值相同");
}
//等价于下面这两种写法
if (ii is 10 && bb is true)
print("元组的值相同");
if (ii is int && ii == 10 && bb is bool && bb)
print("元组的值相同");使用
switch
表达式判断中判断多个变量同时满足再返回什么:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27void Start()
{
print(GetMoney("5折", true, 200)); //输出100
}
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
};
//上面的写法等同于下面的写法,可以发现(discount, isDiscount)被移到了switch前面,而“case 常量:”都被缩减为了“常量 => ”
//public float GetMoney(string discount, bool isDiscount, float money)
//{
// switch ((discount, isDiscount))
// {
// case ("5折", true):
// return money * .5f;
// case ("6折", true):
// return money * .6f;
// case ("7折", true):
// return money * .7f;
// default:
// return money;
// }
//}该模式匹配可以配合 when 关键字来进行一定的逻辑判断
-
位置模式
如果自定义类中实现了解构函数,那么我们可以直接用对应类对象与元组进行
is
判断基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28using UnityEngine;
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 discount, out bool isDiscount) => (discount, isDiscount) = (this.discount, this.isDiscount);
}
public class Lesson11 : MonoBehaviour
{
void Start()
{
DiscountInfo info = new DiscountInfo("5折", true);
if (info is ("5折", true))
{
print("位置模式满足条件");
}
}
}同样我们也可以配合
switch
表达式来处理逻辑1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48using UnityEngine;
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 discount, out bool isDiscount) => (discount, isDiscount) = (this.discount, this.isDiscount);
}
public class Lesson11 : MonoBehaviour
{
void Start()
{
DiscountInfo info = new DiscountInfo("5折", true);
print(GetMoneyNum(info, 300)); //输出150
}
public float GetMoneyNum(DiscountInfo info, float money) => info switch
{
("5折", true) => money * .5f,
("6折", true) => money * .6f,
("7折", true) => money * .7f,
_ => money
};
//上面的写法等同于下面的写法,可以发现info被移到了switch前面,而“case 常量:”都被缩减为了“常量 => ”
//public float GetMoneyNum(DiscountInfo info, float money)
//{
// switch (info)
// {
// case ("5折", true):
// return money * .5f;
// case ("6折", true):
// return money * .6f;
// case ("7折", true):
// return money * .7f;
// default:
// return money;
// }
//}
} -
when(模式匹配添加判断条件)
配合
when
关键字进行逻辑处理,可以添加更多的条件,以进行更细致的条件判断1
2
3
4
5
6
7
8
9public float GetMoneyAdvanceFunc(DiscountInfo info, float money) => info switch
{
(string dis, bool isDis) when dis == "5折" && isDis => money * .5f,
(string dis, bool isDis) when dis == "6折" && isDis => money * .6f,
(string dis, bool isDis) when dis == "7折" && isDis => money * .7f,
//这里的条件判断就可以添加额外的条件表达式,从而进行更细致的条件判断
(string dis, bool isDis) when dis == "8折" && isDis && money > 100 => money * .7f,
_ => money,
};
when
这个关键字不仅可以用于位置模式,还可以用于上面的元组模式,用于添加更多的条件1
2
3
4
5
6
7
8public float GetMoney(string discount, bool isDiscount, float money) => (discount, isDiscount) switch
{
//这里的条件判断就可以添加额外的条件表达式,从而进行更细致的条件判断
("5折", true) when money > 100 => money * .5f,
("6折", true) => money * .6f,
("7折", true) => money * .7f,
_ => money
};