Unity3D学习之路 - C#学习笔记(一)
最近开始学习Unity开发,由于以前一直都是从事C/C++开发,所以对于Unity的脚本语言方面,选择了最相近的C#。由于从头开始学习C#是没有必要的,所以就恶补了一下必须的C#知识^-^
1.C#中使用//(双斜杠)来表明本行的剩余部分代表注释。
2.C#中语句是按顺序执行的,每条语句以分号结尾。
3.C#中的函数执行一系列语句的行为,称为语句块---一对大括号中包含0条或多条语句。
4.一个函数可以通过定义参数来从调用者处接受输入数据,也可以通过定义返回类型来输出数据给调用者。
5.Main函数定义为执行程序的默认入口点。Main函数可以不返回任何值,也可以返回一个整数给执行程序环境。Main函数也可以不定义任何参数,或者定义一个string数组作为参数(该参数将由传递给执行程序的参数填充)。
6.Using指令用于使用命名空间。
7.C#中的标识符以字母或下划线开头,并且大小写敏感。
8.关键字是由编译器保留的名字,不能用作标识符,下面是C#的关键字列表:
9.如果想将关键字作为标识符,那么可以加上前缀@以使它合法,例如:class @class。注意@符号并不构成标识符的一部分,所以@myVariable和myVariable是相同的。
10.一些关键字是上下文相关的,它们不用使用符号@就能够被用作标识符。这些关键字如下:
11.C#中所有的值都是一个特定类型的实例,一个值的含义,以及一个变量可以拥有的所有可能的值,是由它的类型决定的。
12.预定义类型(也叫内建类型)是被编译器特别支持的类型,如int、float、bool等。
13.自定义类型可以包含成员数据和成员函数。需要使用new运算符来创建一个新的自定义类型的实例,当new运算符实例化一个对象后,该对象的构造函数将被调用。构造函数的定义类似于普通函数定义,除了函数名必须和类名相同以及去除了返回类型。
14.在类型的实例上操作的数据成员和函数成员称为实例成员。而不在类型的实例上,但在类型本身上操作的数据成员和函数成员,必须被标记为static。
15.public关键字用于显露成员给其他类使用。
16.C#能够在两个相兼容的类型之间进行转换,转换总是根据一个已存在的值而创建一个新值。转换可以是隐式的或者显式的,隐式的转换自动发生,如int x = 5; long y = x。而显式的转换需要一个映射,如int x = 5; short y = (short)x。一般来说,当编译器能够保证在两个类型之间转换总是成功的,且不丢失任何信息,那么就允许隐式转换,否则的话,就必须使用显式转换。
17.C#中的类型可以分为值类型和引用类型。值类型包括了大多数内置类型(所有的数值类型(int, float等),char类型,bool类型以及struct与enum类型),引用类型包括了所有的class,array,delegate与interface类型。
18.一个值类型的变量或常量包含的内容仅仅是一个值,对一个值类型的实例进行赋值总是会拷贝实际数据到该实例。引用类型的变量或常量包含的内容是对一个拥有实际数据的对象的引用,对一个引用类型的实例进行赋值总是会拷贝引用,而不会拷贝拥有实际数据的对象实例,这就允许多个变量引用同一个对象。
19.一个引用类型的实例可以被设置为null,以表明没有引用任何对象,使用一个为null的实例的成员将产生一个运行时错误。相比之下,一个值类型的实例不能被设置为null。
20.C#中的预定义类型分类:
21.C#预定义的数字类型如下:
22.整型可以使用10进制或16进制标记法,16进制标记法需要加0x前缀,如0x7F。实数可以用10进制或指数标记法,如1e06。
23.浮点数转换为整数将丢弃小数部分,如果想要进行四舍五入的转换,则可以使用System.Convert类。
24.需要注意从1个很大的整数转换为浮点数时可能会丢失精度,如int x = 100000001; float f = x; // 此时f = 100000000。
25.算数运算符(+,-,*,/,%)可以用于所有的数值类型(除了8位和16位的整数类型)。
26.自增,自减运算符用于使数值类型的变量加1或减1。运算符可以放在变量前(++x)或者变量后(x++),取决于想在表达式计算之前还是之后更新变量的值。
27.整数除法总是会丢弃余数。如果除以一个值为0的变量将产生一个运行时错误(DivideByZeroException),除以字面值0将产生编译错误。
28.在运行时,整数类型进行算术运算可能会造成溢出,默认情况下,不会有异常被抛出。C#文档表明对于溢出结果是不可预料的,但是Common Language Runtime(CLR)总是产生一个wraparound行为,也就是说,将最小的int值减1的结果是最大的int值,如int x = int.MinValue; x--; // 此时x = int.MaxValue。
29.checked运算符通知运行时当溢出时抛出一个OverflowException异常,checked运算符可以用于++, --, -(一元), +, -, *, /以及整数类型之间的显示转换。checked运算符可以用于一个表达式或者一个语句块,如:
1 int a = 1000000;
2 int b = 1000000;
3 int c = checked( a * b ); // 用于表达式
4
5 checked
6 {
7 c = a * b; // 用于语句块
8 }
可以使用/checked[+/-]编译选项来检测/不检测程序中所有发生的溢出,如果使用了/checked+来检测程序中所有发生的溢出,而对于某些特定的表达式或语句块又不想使用检测功能,那么可以像checked运算符一样使用unchecked运算符来关闭检测。
30.C#提供了下面这些位运算符:
31.8位和16位的整型包括了byte, sbyte, short和ushort,这些类型自身没有算数运算符,所以C#在需要时会将它们转换为更大的类型,这样就会导致如果接收运算结果的是一个较小的整型时,会发生编译错误,如short x = 1, y = 1; short z = x + y; // 此处编译错误。在这种情况下,为了使加法能够执行,x, y会被隐式的转换为int,这意味着结果也是int,而int不能被隐式的转换为short(因为会导致数据丢失),所以,为了使编译通过,我们需要加上显式转换,short z = (short)(x + y);
32.float和double类有一些常量用于NaN(Not a Number), +∞, -∞, MaxValue, MinValue和Epsilon。当发生除0时将导致结果为无穷值,如:
。当发生0除0或者无穷减无穷时将导致结果为NaN,如
。当使用==时,一个NaN值永远不会等于另一个值,即使是另一个NaN值,所以如果要测试一个值是否为NaN,必须使用float.IsNaN或者double.IsNaN函数。当使用Object.Equals函数时,也可以判断两个NaN值是否相等,如object.Equals (0.0/0.0, double.NaN) // true。
33.float类型适用于科学计算,而decimal类型适用于金融计算或者表示那些人为的值,下面是double类型与decimal类型的区别:
34.由于float和double类型的数值在内部是以2为基表示的,所以许多以10为基的小数部分字面值无法被精确的表示,如
,这就是为什么float和double类型不适用于金融计算的原因。相比之下,由于decimal类型的数值是以10为基表示的,所以这种情况不会出现。
35.C#的bool类型是一个可以被指定为true或者false的逻辑值。尽管一个bool类型仅需要1位的存储空间,但是运行时将使用1个字节的存储空间,因为这是运行时和处理器可以有效工作的最小单位。所以为了避免空间上的浪费,C#提供了一个BitArray类,该类位于System.Collections命名空间下,旨在只使用1位存储空间表示每个bool类型的值。
36.对于引用类型,是否相等,默认情况下是取决于所引用的对象是否相同,而不是对象内部的实际数据。因此,一个对象的两个拥有相同数据的实例被认为是不相等的,除非该对象所属的类型重载了==运算符以达到使他们相等的效果。
37.相等和比较运算符,==, !=, <, >, <=, >=,可以用于所有的数值类型,但是用于实数时需要谨慎小心(参见34)。这些运算符也可以用于enum(枚举)类型成员,比较的是他们代表的整型数值。
38.&&和||运算符用于测试条件与和条件或,他们是短路运算符,也就是说,当前一个表达式不满足时,后续表达式将不再计算,如if ( a && b ),如果表达式a为假,那么表达式b将不会计算,这是十分有用的,例如:if (sb != null && sb.Length > 0),可以避免抛出NullReferenceException异常。&和|运算符也可用于测试条件与和条件或,但是他们不是短路运算符,所以,一般很少用于条件测试。还有一个三目运算符,形式如q ? a : b,当q为真时,a将被计算,否则b将被计算。
39.C#的char类型代表一个Unicode字符,占用2个字节。一个char的字面表示在一个单引号中,如char c = 'A';转义字符用来表示那些不能显示的字符,一个转义字符是一个反斜杠紧跟一个字符,具有特定的含义,转义字符表如下:
。\u(或\x)转义字符允许你通过使用4位16进制来指定任意的Unicode字符,如char newLine = '\u000A';
40.当一个数值类型可以容纳一个unsigned short类型的值时,从char到该数值类型就可以隐式转换。否则的话,就需要显示转换。
41.string类型表示一个不可变的Unicode字符序列。一个string的字面表示在一个双引号中,如string s = "hello";尽管string是引用类型,而不是值类型,但是它的==运算符却遵循值类型的比较语义,如string a = "test", b = "test"; Console.Write (a == b); // True。转义字符同样也可以用在string类型中,如string a = "\\\\server\\fileshare";C#还提供逐字字符串字面值,以@开头并且不再解析转义字符,如string b = @"\\server\fileshare";和上面的字符串a是等价的。
42.+运算符用于连接两个字符串,如string a = "s" + "w";可能某个操作数不是string类型,那么该操作数类型的ToString函数将被调用,如string a = "s" + 5;等价于string a = "s" + 5.ToString();因为string类型是不可变的,所以多次的使用+运算符构建一个新的string是十分低效的。取而代之的,可以使用System.Text.StringBuilder类型,这代表了一个可变的字符串,以及拥有可以高效的添加,删除,插入,替换子串的方法。
43.string类型不支持<和>运算符来进行比较操作,必须使用string类型的CompareTo函数。
44.字符串的索引返回特定位置上的字符,如Console.Write ("word"[2]); // r。
45.切记:string类型代表的字符串是不可变的,所有操作字符串的函数将返回一个新的字符串,原来的字符串不会被改变。
46.一个数组(Array)代表一个特定类型的固定数量的元素。一旦数组被创建,它的长度就不能被改变了。数组元素总是被存储在连续的内存块中,以供高效的存取。一个数组以元素类型紧跟方括号来表示,如char[] vowels = new char[5]; 方括号也用于数组索引,存取一个特定位置的元素,如vowels[0] = 'a'; 在运行时所有的数组索引都会进行范围检测,如果使用了一个无效的索引,那么将抛出一个IndexOutOfRangeException异常。
47.数组的初始化表达式可以方便的同时声明和赋值一个数组,如char[] vowels = new char[] {'a','e','i','o','u'}; 或者更简单的方式char[] vowels = {'a','e','i','o','u'}; 可以使用for循环来遍历一个数组中的所有元素,同时,由于数组总是实现了IEnumerable<T>,所以也能够使用foreach来枚举数组成员:
1 char[] vowels = {'a','e','i','o','u'};
2
3 for (int i = 0; i < vowels.Length; i++)
4 {
5 Console.Write (vowels[i]);
6 }
7
8 foreach (char c in vowels)
9 {
10 Console.Write (c);
11 }
48.创建一个数组总是会使用默认值来预初始化每个元素,一个类型的默认值就是在内存中每一位都是0,对于值类型来说,就是0,对于引用类型来说,就是null。无论元素类型是什么,数组自身总是引用类型的。
49.多维数组有两种形式:矩形数组(Rectangular arrays)和不规则数组(Jagged arrays)。矩形数组声明时使用逗号来分割每一维,如int[,] matrix = new int [3, 3]; 一个矩形数组可以像下面这样初始化:
int[,] matrix = new int[,] { {0,1,2}, {3,4,5}, {6,7,8} }; // 更简洁的方式 int[,] matrix = { {0,1,2}, {3,4,5}, {6,7,8} };
不规则数组使用连续的方括号来代表每一维,如声明一个2维数组,最外维的大小为3:int[][] matrix = new int[3][]; 可以发现,声明时并没有指定内维的大小,与矩形数组不同的是,每个内维数组可以使任意大小的。因为内维数组被隐式初始化为null而不是一个空数组,所以内维数组必须手动创建:
int[][] matrix = new int[3][]; for (int i = 0; i < matrix.Length; i++) { matrix[i] = new int [3]; // 创建内维数组 for (int j = 0; j < matrix[i].Length; j++) matrix[i][j] = i * 3 + j; }
不规则数组可以像下面这样初始化:
int[][] matrix = new int[][] { new int[] {0,1,2}, new int[] {3,4,5}, new int[] {6,7,8} }; // 更简洁的方式 int[][] matrix = { new int[] {0,1,2}, new int[] {3,4,5}, new int[] {6,7,8} };
50.还有另一个简洁的数组初始化表达式,它省略了new关键字之后的类型名,让编译器去推断数组类型。当传递数组类型的参数时,这是一个十分有用的缩写:
void Foo (char[] data) { ... } Foo ( new[]{'a','e','i','o','u'} );