购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

建议32:总是优先考虑泛型

泛型的优点是多方面的,无论是泛型类还是泛型方法都同时具备可重用性、类型安全和高效率等特性,这都是非泛型类和非泛型方法无法具备的。本建议将从可重用性、类型安全和高效率三个方面来阐述:在实际的编码过程中为何总是应该优先考虑泛型。

以可重用性为例,比如要设计一个集合类:


class MyList

{

int[]items;

public int this[int i]

{

get{return items[i];}

set{this.items[i]=value;}

}

public int Count

{

get{return items.Length;}

}

///省略其他方法

}


该类型只支持整型,如果要让类型支持字符串,有一种方法是重新设计一个类。但是这两个类型的属性和方法都是非常接近的,如果有一种方法可以让类型接收一个通用的数据类型,这样就可以进行代码复用了,同时类型也只要一个就够了。泛型完成的就是这样一个功能。以上版本的泛型的实现方法是:


class MyList<T>

{

T[]items;

public T this[int i]

{

get{return items[i];}

set{this.items[i]=value;}

}

public int Count

{

get{return items.Length;}

}

///省略其他方法

}


可以把T理解为一个占位符,在C#泛型编译生成的IL代码中,T就是一个占位符的角色。在运行时,即时编译器(JIT)会用实际代码中输入的T类型来代替T,也就是说,在由JIT生成的本地代码中,已经使用了实际的数据类型。我们可以把MyList<int>和MyList<string>视做两个完全不同的类型,但是,这仅是对本地代码而言的,对于实际的C#代码,它仅仅拥有一个类型,那就是泛型类型MyList<T>。

以上从代码重用性的角度论证了泛型的优点。继续从类型MyList<T>的角度论述,如果不用泛型实现代码重用,另一种方法是让MyList的编码从object的角度去设计。在C#的世界中,所有类型(包括值类型和引用类型)都是继承自object,如果要让MyList足够通用,就需要让MyList针对object编码,代码如下所示:


class MyList

{

object[]items;

public object this[int i]

{

get{return items[i];}

set{this.items[i]=value;}

}

public int Count

{

get{return items.Length;}

}

///省略其他方法

}


这会让下面的代码编译通过:


list[0]=123;

list[1]="123";


由上面两行代码带来的问题就是非“类型安全性”。该问题实际在建议20中已经详细论述过了。让类型支持类型安全,可以让程序在编译期间就过滤掉部分Bug,同时,也能让代码规避掉“转型为object类型”或“从object转型为实际类型”所带来的效率损耗。尤其是涉及的操作类型是值类型时,还会带来装箱和拆箱的性能损耗。

例如,上文代码中的


list[0]=123;


就会带来一次装箱操作,因为它首先被转型为object,继而存储到items这个object数组中去了。

泛型为C#语言带来的是革命性的变化,FCL之后的很多功能都是借助泛型才得到了很好的实现,如LINQ。LINQ借助于泛型和扩展方法,有效地丰富了集合的查询功能,同时避免了代码爆炸并提升了操作的性能。我们在设计自己的类型时,应充分考虑到泛型的优点,让自己的类型成为泛型类。 mCiWVbGRitRp0AQLb7xHdDkgiwt7ijWQCzcisqhfNqTw9cRFe74EZ3OzxnHT9f6Y

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开