C# 高级语法特性(一)
打算持续更新一个专栏,旨在分享对C#这门编程语言的理解,巩固自己的C#知识体系以用于之后可能的Unity游戏开发(所以我对C#的讨论会更多地基于它在Unity这个游戏引擎的实际应用),并讨论一些C#区别于其它语言的特点。既然是针对于C#,自然不涉及太多各语言都包含的语法知识和面向对象基础,更多会讨论一些进阶知识,整理C#的高级语法特性,故该专栏可能不适用于编程新手。其中可能会总结一些其他书籍、课程中分享的经验,甚至部分搬运到专栏中来。对文章中可能出现的任何错误和纰漏,欢迎大家指出和纠正。

Unity对C#版本的支持
Unity 4.x 支持到 C# 2.0
Unity 5.x 支持到 C# 3.0,
Unity 2017.x 支持到 C# 6.0
Unity 2018.x 到 C# 7.2
C#和其它语言一样,自然也经历过版本的迭代,而编程语言的第一版一般都是核心部分,也是最常用的部分。
C# 1.0
罗列一下1.0版本中的语法特性:
类(class)
结构(struct)
接口(interface)
属性(property)
事件(event)
委托(delegates)
表达式
语句
特性(属性)(Attribute)
类
大概会涉及到面向对象编程语言中共有的一些话题如:访问权限、抽象类、内部类、继承多态等,就无需过多介绍了。提一下C#中一个特殊的关键字partial,其实也很简单,它可以实现类的逻辑拆分到不同的文件。
结构
熟悉C或者C++的开发者可能会对结构体比较熟悉,C#中也有结构体这个概念,其中最关键的一点:值类型。
在Unity开发中,我们要对一个游戏对象的位置进行改变时,不得不写成如下形式:
Vector3 pos = transform.position;
pos.x = 2.0f;
transform.position = pos;
而不是
transform.position.x = 2.0f;
在这里,无法直接对结构体中的单一变量赋值。总结C#结构体的一些关键点:
值类型
结构不能为null
声明变量时,本身就有值了
分配给新变量时,是深拷贝,并且对新副本所做的任何修改不会更改原始副本的数据
在为属性器时,不能局部赋值
接口
接口需要提一点:显式实现和隐式实现。显式实现在Unity中其主要的应用场景是防止误调用,如:
public interface ITask {
void Run();
}
public class Task : ITask{
void ITask.Run(){
...
}
public class TaskRunner{
public static void RunTask(ITask task){
task.Run();
}
}
void Start(){
var task = new Task();
// task.Run(); 显式实现,无法直接调用
TaskRunner.RunTask(task); // 用专门的执行器去调用
}
接口的显式实现降低了方法调用的权限,避免开发者误调用。
属性器
属性器的优势在于隔离类内部的变化,也体现了OOP的封装性。如:
public class A{
public int a;
}
此时在另一处访问了此属性:
void Start(){
var ob = new A() { a = 1 } ;
Debug.Log(ob.a);
}
当我们需要对属性a的计算方法进行改变时:
public class A{
public int a{
get{
return 1 - b ;
}
}
public int b;
}
此时我们只需在声明处传入b的值即可,而无需再在访问属性a的地方对其进行任何更改。

事件、委托、特性会放在下一篇专栏中进行总结。