1、 关于变量的命名:我所选的“教科书”上给出了以下的建议,据说是为了与公共语言规范 (Common Language Specification, CLS)的相容性:
- 不要使用下划线(受VC的影响,偶的变量名中经常出现下划线,确实不方便)。
- 不要创建只是大小写区别的标识符。
- 使用小写字母作为变量名的首字母。
- 包含多个单词的标识符中,第二个单词开始,每个单词都采取首字母大写的形式(camelCase记号法)。
- 不要使用匈牙利记号法(Hungarian notation)(又是VC的遗毒!)。
2、 未赋值的局部变量:C#中不允许使用未赋值的变量。一个变量必须赋值才能使用,否则无法编译。就是所谓的明确赋值规则(Definite Assignment Rule)。
3、 C/C++中可以隐式转换的,在C#中不一定行,例如:
1: float var;
2: var = 2.4;
这样的语句在C#中是不能编译的,必须改为
1: float var;
2: var = 2.4F;
4、 C/C++中,不可以对浮点数使用%操作符,但在C#中可以。
5、 C#不支持全局方法,即所有的方法必须在一个类的内部,否则代码无法编译。
6、 C++接受了C中在缺少数据类型情况下默认为int的传统(尽管C++反对这样做),但是在C#中这是不被允许的。例如:如果你的方法不返回任何值,那么必须使用 void关键字。下面的代码是无法编译的:
1: showResult( int answer )
2: {
3: //…
4: }
7、 注意C#中的短路求值(short circuiting),实际上在C/C++中也应该注意这一点。
8、 C/C++中的if语句中表达式可以是整数,编译器能自动将整数值转换为true,或是false,但在C#中必须是布尔表达式。假如你在if语句中不慎写了一个赋值表达式,而不是执行一个相等性测试,C#编译器也能识别你的错误。
9、 C#存在不准贯穿(fall through)的规则,必须为switch语句中的每个case(包括default case)都提供一个break语句。减少自由度,来增加代码的安全。
10、 C#可以有选择地启用溢出检查功能。可以在工程中全局设置,也可以随时使用checked和unchecked关键字来选择性地打开和关闭程序的一个特定部分的溢出检查。这些关键字将覆盖编译器选项。
11、异常抛出时,会改变程序的执行流程。就意味着不能保证当一个语句结束之后,其后面的一个语句肯定会运行,因为前一个语句可能抛出一个异常。C#提供了关键字finally,Finally块要紧接在try块之后,或者紧接在try块之后的最后一个catch处理程序之后,这样finally块就总会执行。
12、 C#中public或者private关键字之后不要添加冒号。必须为每个声明重复这些关键字。private是默认的,可以省略,但不推荐这样做。
13、 C#中的类字段自动初始化为0或者null(视类型而定)。当然最好显式初始化。
14、 C#支持部分类,一个类拆分到多个文件中之后,在每个文件中使用partial关键字来定义类的不同部分。
15、 .NET Framework推荐了以下字段和方法命名约定,是以类成员的可访问性为出发点来考虑的:
- public性质的标识符应该以大写字母开头。
- 非public性质的标识符(其中包括局部变量)应该以小写字母开头。
当然也有例外,就是类名应该大写字母开头,所以构造函数(即使是private的)也应该以大写字母开头。
16、 C#中可以定义static类,其中只能包含static成员。不能包含任何实例数据或方法。
17、 C#中“引用”和C++中的“引用”差不多(但写法不同),只是在C++中,除了“引用”,还有一个更强大的东东——“指针”。C#中没有“指针”,除了“引用类型”(“间接类型”),就是“值类型”(“直接类型”)。
18、 C#中向一个ref参数传递一个实参时,实参也必须附加ref关键字作为前缀。
19、 C#中的out的关键可以实现方法本身对参数的初始化。out和ref非常相似,可以使参数成为实参的一个别名。
20、 C#中要明确这一点,值类型是存在于堆栈(stack)中,而引用类型的实际内容是存在于堆(heap)中,所以对值类型变量的装箱(Boxing)实际上是在堆中创建了它的一个副本。
21、 访问已经装箱的值,必须进行一次强制类型转换(cast),这就是拆箱(Unboxing)。
22、 C#中的枚举和C/C++中的枚举定义时差不多(只是定义后可以不加分号),但在使用上有不同。所有枚举直接量名称都要使用它们的枚举类型来限制范围,这样就允许不同的枚举类型包含同名的直接量,这一点要优于C++。C#中的枚举还可以选择基础类型,以节省内存。
23、 C#中的结构和类语法上相似,但两者有些重要的差别:
- 不能为结构声明一个自己的默认构造函数(无参数构造函数),因为编译器将始终生成一个默认的构造函数。这一点也是和C++中的结构的区别。结构的默认构造函数和类一样,总是将字段设为0、false或者null。你可以为结构提供自己的非默认构造函数,用以初始化为其它的值。但是如果你在自己的构造函数中没有初始化一个字段,编译器将不再帮你初始化它。这意味着必须在结构的所有构造函数中显式地初始化所有字段,否则就会有编译器错误(还不错,在编译时会报错)。
- 在一个类中,可以在声明的同时初始化实例字段,但在struct中不能这样做。C++中的类声明同时也是不能初始化成员变量的,当然有例外,如果一个静态数据成员既是const类型又是整型,那么声明就可以初始化,但是应该要类的定义文件中对其进行定义。
24、 C#中结构的初始化,要注意,因为是值类型,所以如果不用new的话,编译器不会为你做结构字段的初始化工作。
25、 C#中的数组声明和C/C++中的不同,数组的大小不是声明的一部分。实际上C#中的数组是new出来的。
26、 C#中的数组是new出来的,所以其初始化方式和C/C++也不相同。
1: int[] dogs = new int[4] { 1, 2, 3, 4 };
27、 C#提供了foreach语句来遍历一个数组的所有元素。
28、 C#中将C++中原来模板中才有的东东,吸收了进来,数组,集合,队列……,不多说了。
29、C#中的参数数组和C/C++中的数组作参数有不同,C/C++数组做参数一般要传入数组的大小,而C#中由于数组已经是一个对象,所以可以不用传入数组长度,相当于C/C++中的变长参数列表。C#中为了省去自己编写额外的代码来填充传入的数组,提供了params关键字,要注意的是:
- 只能在一维数组上使用使用params关键字。
- 不能重载一个只基于params关键字的方法。params关键字不构成方法的签名的一部分。
- 不允许ref或out parmas数组。
- params数组必须是方法的最后一个参数(也就是说,每个方法只能有一个params数组参数)。
- 编译器会检查并拒绝任何可能有歧义的重载。如下,如果传递两个参数,将无法分辨具体应该调用哪一个:
1: // 编译错误
2: public static int Min( params int[] paramList )
3: {
4: //…
5: }
6:
7: public static int Min( int first, params int[] paramList )
8: {
9: //…
10: }
- 非params方法总是优先于一个params方法。如下,假如传递两个参数,那么调用的肯定是Min方法的第一个版本。假如传递其他任意数量的int参数,则调用第二个版本(其中包括调用方法时无参数的情况):
1: public static int Min(int leftHandSide, int rightHandSide)
2: {
3: //…
4: }
5:
6: public static int Min(params int[] paramList)
7: {
8: //…
9: }
- 声明不带params数组参数的方法,可以避免编译器创建和填充太多的数组。
30、 C#中也可以继承和派生。但和C++不同,一个类最多只允许从一个类中派生;不允许从两个或者更多的类中派生。而且,C#中继承总是隐式为public,不可以显式指定。(C++的多重和公有、私有、保护继承总是把人搞晕,这下清静了。)