CS5L6——CSharp 1~4 功能和语法

C# 1~4版本中的功能和语法,大多数我们已经在C#四部曲中学习完毕
命名和可选参数可以帮助我们少写一些重载函数
动态类型可以让我们在某些情况下节约代码量
但是由于要使用.Net 4.x(.NET Framework),并且IL2CPP不支持,所以不建议使用它,但是如果有特殊需求不得不用,那我们只有退而求其次

本章代码关键字

1
dynamic    //动态类型,编译时不会检查该对象的类型,与该对象相关的操作都将一起打包,只在运行时进行评估

最低支持的C#版本

只要是Unity 5.5及以上的版本,就支持C# 4版本

C# 1~4的功能和语法

注意:
在这里不会提及所有的内容
主要会提及Unity开发中会用到的一些功能和特性
对于一些不适合在Unity中使用的内容会省略

  • C# 1 —— 委托、事件(C#进阶)
  • C# 2 —— 泛型、匿名方法、迭代器、可空类型(C#进阶)
  • C# 3 —— 隐式类型、对象集合初始化、Lambda表达式、匿名类型(C#进阶),
    自动实现属性、拓展方法、分部类(C#核心),Linq相关的表达式树(以后专门讲)
  • C# 4 —— 泛型的协变和逆变(C#进阶)、命名和可选参数、动态类型

命名和可选参数

有了命名参数,我们将不用匹配参数在所调用方法中的顺序
每个参数可以按照参数名字进行指定

1
2
3
4
5
6
7
8
public void Test(int i, float f, bool b) { }

private void Start
{
Test(1, 1.2f, ture); //在以前,我们需要按照参数声明顺序分别填入各个参数
Test(f: 3.3f, i: 5, b: false); //而通过指定参数的名字,我们可以不用按照顺序去填入参数
Test(b: false, f: 3.4f, i: 3);
}

命名参数可以配合可选参数使用,让我们做到跳过其中的默认参数直接赋值后面的默认参数

1
2
3
4
5
6
7
public void Test2(int i , bool b = true, string s = "123") { }

void Start()
{
Test2(1, true, "234"); //在以前,我们如果想不修改前一个可选参数,而只修改后面的可选参数,我们不得不将前面参数的默认值填上去
Test2(1, s: "234"); //而通过指定参数的名字,我们可以做到跳过其中的默认参数直接赋值后面的默认参数
}

动态类型

**关键词:**​dynamic

作用: 通过dynamic​类型标识变量的使用和对其成员的引用绕过编译时类型检查,改为在运行时解析这些操作。
在大多数情况下,dynamic​类型和object​类型行为类似,任何非Null​表达式都可以转换为dynamic​类型。
dynamic​类型和object​类型不同之处在于,编译器不会对包含类型 dynamic​ 的表达式的操作进行解析或类型检查
编译器将有关该操作信息打包在一起,之后这些信息会用于在运行时评估操作。
在此过程中,dynamic​ 类型的变量会编译为 object​ 类型的变量。
因此,dynamic​ 类型只在编译时存在,在运行时则不存在。

注意:

  1. 使用dynamic​功能,需要将Unity的.Net API兼容级别切换为.Net 4.xUnity2021版为.NET Framework)
  2. IL2CPP 不支持 C# dynamic​​ 关键字。它需要 JIT 编译,而 IL2CPP 无法实现
  3. 动态类型是无法自动补全方法的,我们在书写时一定要保证方法的拼写正确性

该功能我们只做了解,不建议大家使用

1
2
3
4
5
6
7
dynamic dyn = 1;
object obj = 2;

dyn += 2; //我们可以在编译前对动态类型变量做任意操作,IDE不会帮我们检查,但该对象真正对应的类型必须真的存在该操作,否则运行会报错
print(obj.GetType()); //要注意,IDE可以帮助我们补全.GetType()并标记,因为编译时会类型检查,且该类存在该方法
print(dyn.GetType()); //而在这里输入的.GetType()IDE不会自动补全,也不会将其标黄,因为IDE不会在编译时检查类型,你只能自己确保该类型真的有该方法
print(dyn); //我们也可以将动态类型变量作为某个函数的参数,而IDE也不会帮我们检查该对象是否真的可以作为参数

好处:
动态类型可以节约代码量,当不确定对象类型,但是确定对象成员时,可以使用动态类型****通过反射处理某些功能时,也可以考虑使用动态类型来替换它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test1
{
public void TestFunc() { }
}

public class Test2
{
public void TestFunc() { }
}

public class Lesson3 : MonoBehaviour
{
void Start()
{
object t = new Test1(); //在以前我们通过object获取到一个对象,或者反射获取到一个不确定类型的对象
//t.TestFunc(); //我们是不能直接使用对象原本类里的内部的方法
((Test1)t).TestFunc(); //我们需要通过类型转换或者反射等手段转换成原类型再使用其中的方法

dynamic tmp = t; //而当不确定对象类型,但是确定对象成员时,就可以使用动态类型,不需要转换类型
tmp.TestFunc(); //动态类型对象编译时不会检查类型,而会将对象与该对象相关的操作进行打包,运行时才会评估操作
}
}