一.C# 1~4的一些新功能
1.命名参数:
void Start() { //命名参数可以实现打乱参数顺序,使用[参数名:]指定参数 Test01(b: 2, c: 1, a: 0); //命名参数一般使用于有多个默认值的参数的情况 Test02(1, p: 3); } private void Test01(int a, int b, int c) { } private void Test02(int m , int n = 2, int p = 3, int q = 4) { }
2.动态类型
void Start() { //动态类型dynamic,这个类型在运行时检查类型 //和var不同,var在编译时检查类型,也就是说,虽然我们写的是var类型,但是在编译时实际类型是明确的,编辑器中鼠标指到var上也能显示实际类型,而dynamic类型在编译时实际类型不明确,鼠标指到dynamic上不会显示实际类型 //dynamic类型在编译时会编译为object类型,但是在代码中可以点出各种方法(和object的区别在于,dynamic可以是任意类型,并可以直接调用这个类型的所有方法,object类型需要转型) //dynamic类型可以用于替换反射操作 dynamic a = 1; var b = 1; a.Test01(1, 2);//编辑器中并不会报错 } private void Test01(int a, int b, int c) { }
二.C# 5的一些新功能
1.Task任务类
void Start() { //简介:Task是对线程的封装,以便更为方便地管理线程,一个task就是一个线程 //创建task //方法一:直接new一个Task,需要传入线程执行地委托 Task task01 = new Task(Test01); task01.Start(); //方法二:使用静态方法Run创建task并直接开启 var task02 = Task.Run(Test01); //方法三:使用Factory创建并直接开启 var task03 = Task.Factory.StartNew(Test01); //说明:以上三种方式都可以通过泛型指定返回值,创建有返回值的task var task04 = Task.Run<int>(Test02); //通过Result获取返回值 print(task04.Result);//注意:通过Result获取返回值时,如果此时task还没有执行得到返回值,主线程会阻塞等待task执行直到得到返回值;如果这时task是一个死循环,主线程会卡死 //同步执行task //使用new创建的task可以同步执行 var task05 = new Task(Test01); task05.RunSynchronously();//使用RunSynchronously方法同步执行线程,这种方式执行的线程主线程会等待其执行完毕再继续执行,和在主线程中执行代码类似 //阻塞执行task var task06 = Task.Run(Test01); task06.Wait();//这个方法会让主线程在等待task06的逻辑执行完毕后再执行之后的代码 Task.WaitAny(task01, task02, task03, task04, task05, task06);//这个方法会让主线程在等待传入的task中的任意一个任务完成后继续执行之后的代码 Task.WaitAll(task01, task02, task03, task04, task05, task06);//这个方法会让主线程在等待传入的所有task都执行完成后再继续执行之后的代码 } private void Test01() { } private int Test02() { return 1; }
2.异步方法Async和await
//在方法名前使用async关键字标识这是一个异步方法 //使用async修饰的函数中可以没有await关键字 //异步方法名称建议以Async结尾 //异步方法的返回值只能是void或者task //异步方法的变量不能使用ref或者out修饰 private async void TestAsync() { //await经常和task配合使用 //await可以开启一个新线程,并挂起异步方法,将控制权返回给调用者,等待开启的新线程逻辑执行完毕之后继续执行当前异步方法 await Task.Run( () => { print($"新线程逻辑执行,当前时间:{Time.time}"); Thread.Sleep(1000); }); print($"异步方法执行完毕,当前时间:{Time.time}"); } void Start() { TestAsync(); }
三.C# 6的一些新功能
1.静态导入
using UnityEngine; //引用命名空间时,使用静态导入,之后可以直接访问其静态成员 using static UnityEngine.Mathf; public class Test1 : MonoBehaviour { void Start() { //静态导入了Mathf类后,可以直接不用指明类名就可以使用其中的方法 Clamp01(0.5f); } }
2.异常筛选器
void Start() { try { } //使用when关键字对捕获到的异常进行限制 catch (Exception e) when (e.Message.Contains("301")) { } catch (Exception e) when (e.Message.Contains("404")) { } //最后一个catch可以不加when关键字进行筛选,意为使用默认方式处理剩余的异常 catch (Exception e) { } finally { } }
3.nameof关键字
void Start() { int i = 0; //使用nameof关键字直接得到变量类型名称 print(nameof(i)); //也可以得到方法名 print(nameof(List<int>.Add)); //可以得到类名 print(nameof(List<int>)); }
四.C# 7的一些新功能
1.字面值改进
void Start() { //在字面值上添加_作为分隔符方便阅读 int i = 1_2345_6789; }
2.out的快捷使用
void Start() { //在使用out参数时可以直接在给定参数的同时声明变量 if(TryGetInt32(out var num)) { print(num); } } private bool TryGetInt32(out int num) { num = 1; return true; }
3.弃元
void Start() { //使用_替换不想使用的out参数 if(TryGetInt32(out _)) { print(""); } } private bool TryGetInt32(out int num) { num = 1; return true; }
4.ref关键字将值类型改为引用类型
void Start() { //使用ref关键字将值类型改为引用类型 int i = 100;//值类型i ref int j = ref i;//引用类型j }
5.本地函数
void Start() { //直接使用本地函数 int i = 0; Test(); //本地函数,即函数中声明的函数,可以使用原函数中的所有局部变量 void Test() { print(i); } }
6.元组
void Start() { //使用括号将多个变量组合成一个元组(相当于一个简单的结构体) (int, float, bool) i = (1, 2f, true); //使用item1\item2\item3...取用元组中的内容 print($"{i.Item1}|{i.Item2}|{i.Item3}"); //可以给元组中的元素取别名 (int num, float time, bool health) j = (1, 2f, false); //使用别名取用 print($"{j.num}|{j.time}|{j.health}"); }
7.模式匹配
void Start() { //常量模式:[is 常量]用于判断是否是某个值 int i = 1; if(i is 1) { print(i); } //类型模式:[is 类型名 变量名]用于判断变量是否是某个类型,是的话同时将其转型为新类型 object j = 2; if(j is int k) { print(k); } //类型模式和switch语句的配合 switch (j) { case int m: print(nameof(Int32)); break; case float n: print(nameof(Single)); break; case bool b: print(nameof(Boolean)); break; default: print(""); break; } //var模式:[is var 变量名]相当于将变量转存 bool d = true; if(d is var e) { print(e.GetType().Name); } }