Microsoft C#编码规范 下载本文

Page 25

?一定请在向用户输出结果时,使用基于StringComparison.CurrentCulture的字符串操作。

?一定请在比较语言无关字符串(符号,等)时,使用非语言学的StringComparison.Ordinal或者

StringComparison.OrdinalIgnoreCase值,而不是基于CultureInfo.InvariantCulture的字符串操作。一般而言,不要使用基于StringComparison.InvariantCulture的字符串操作。一个例外是当你坚持其语言上有意义,而与具体文化无关的情况。

?一定请使用String.Equals的重载版本来测试2个字符串是否相等。比如,忽略大小写后,判断2个字符串是否相等,

if(str1.Equals(str2, StringComparison.OrdinalIgnoreCase))

If(str1.Equals(str2, StringComparison.OrdinalIgnoreCase))Then

?一定不要使用String.Compare或CompareTo的重载版本来检验返回值是否为0,来判断字符串是否相等。这2个函数是用于字符串排序,而非检查相等性。

?一定请在字符串比较时,以String.ToUpperInvariant函数使字符串规范化,而不用String.ToLowerInvariant。

3.7 数组和集合

?您应该在低层次函数中使用数组,来减少内存消耗,增强性能表现。对于公开接口,则偏向选择集合。

集合提供了对于其内容更多的控制权,可以随着时间改善,提高可用性。另外,不推荐在只读场景下使用数组,因为数组克隆的代价太高。

然而,如果您把熟练开发者作为目标,对于只读场景使用数组也是个不错的主意。数组的内存占用比较低,这减少了工作区,并因为运行时的优化能更快的访问数组元素。

? 2016 Microsoft Corporation. All rights reserved.

Page 26

?一定不要使用只读的数组字段。字段本身只读,不能被修改,但是其内部元素可以被修改。以下示例展示了使用只读数组字段的陷阱:

Bad:

publicstaticreadonlychar[] InvalidPathChars = { '\\\, '<', '>', '|'};

这允许调用者修改数组内的值:

InvalidPathChars[0] = 'A';

您可以使用一个只读集合(只要其元素也是不可变的),或者在返回之前进行数组克隆。然而,数组克隆的代价可能过高:

publicstatic ReadOnlyCollection GetInvalidPathChars() {

return Array.AsReadOnly(badChars); }

publicstaticchar[] GetInvalidPathChars() {

return(char[])badChars.Clone(); }

?您应该使用不规则数组来代替使用多维数组。一个不规则数组是指其元素本身也是一个数组。构成元素的数组可能有不同大小,这样相较于多维数组能减少一些数据集的空间浪费(例如,稀疏矩阵)。另外,CLR能够对不规则数组的索引操作进行优化,所以在某些情景下,具有更好的性能表现。

// 不规则数组

int[][] jaggedArray = {

newint[] {1,2,3,4}, newint[] {5,6,7}, newint[] {8}, newint[] {9} };

Dim jaggedArray AsInteger()() = NewInteger()() _ { _

NewInteger() {1, 2, 3, 4}, _

? 2016 Microsoft Corporation. All rights reserved.

Page 27

NewInteger() {5, 6, 7}, _ NewInteger() {8}, _ NewInteger() {9} _ }

// 多维数组

int [,] multiDimArray = {

{1,2,3,4}, {5,6,7,0}, {8,0,0,0}, {9,0,0,0} };

Dim multiDimArray(,)AsInteger = _ { _

{1, 2, 3, 4}, _ {5, 6, 7, 0}, _ {8, 0, 0, 0}, _ {9, 0, 0, 0} _ }

?一定请将代表了读/写集合的属性或返回值声明为 Collection或其子类,将代表了只读集合的属性或返回值声明为ReadOnlyCollection或其子类。

?您应该重新考虑对于ArrayList的使用,因为所有添加至其中的对象都被当做System.Object,当从ArrayList取回值时,这些对象都会拆箱,并返回其真实的值类型。所以我们推荐您使用定制类型的集合,而不是ArrayList。比如,.NET 在System.Collection.Specialized命名空间内为String提供了强类型集合StringCollection。

?您应该重新考虑对于Hashtable的使用。相反,您应该尝试其他字典类,例如StringDictionary,NameValueCollection,HybridCollection。除非Hashtable只存储少量值,最好不要使用Hashtable。

?您应该在实现集合类型时,为其实现IEnumerable接口,这样该集合便能用于LINQ to Objects。

? 2016 Microsoft Corporation. All rights reserved.

Page 28

?一定不要在同一个类型上同时实现IEnumerator和IEnumerable接口。同样,也不要同时实现非泛型接口IEnumerator和IEnumerable。所以,一个类型只能成为一个集合或者一个枚举器,而不可二者皆得。

?一定不要返回数组或集合的null引用。空值数组或集合的含义在代码环境中很难被理解。比如,一个用户可能假定如下代码能够正常运行,所以应该返回一个空数组或集合,而不是null引用。

int[] arr = SomeOtherFunc(); foreach(int v in arr) { ... }

3.8 结构体

?一定请确保将所有实例数据设置为0值,false或者是null。当创建结构体数组时,这样能防止意外创建了无效实例。

?一定请为值类型实现IEquatable接口。值类型的Object.Equals方法会引起装箱操作。且因为使用了反射特性,所以其默认实现效率不高。IEquatable.Equals 较其有相当大的性能提升,且其实现可以不引发装箱操作。

3.8.1 结构体vs类

?一定不要定义结构体,除非其具有如下特性:

? 它在逻辑上代表了一个单值,类似于原始类型(例如,int、 double,等等)。 ? 其示例大小小于16字节。 ? 它是不可变的。

? 它不会引发频繁的装箱拆箱操作。

? 2016 Microsoft Corporation. All rights reserved.