【记】《.net之美》之读书笔记(二) C#中的泛型

上一篇读书笔记,很多小伙伴说这本书很不错,所以趁着国庆假期,继续我的读书之旅,来跟随书中作者一起温习并掌握第二章的内容吧。

一.理解泛型

1.为什么要使用泛型?-----通过使用泛型,可以极大地提高代码的重用度,同时还可以获得强类型的支持,提升了应用程序的性能,避免了隐式的装箱、拆箱,以及运行时的类型转换错误。

2.为什么要有泛型? -----以简单的数组排序为例,第一次我们可能会要求对int型数组进行排序,然后我们很快的写出了答案,

第二次,又要求我们对byte[]数组进行排序,这时候我们可能会思考下,是不是要优化我们的设计思想,但是还不至于修改,我们还是快速的将int[]数组的排序代码进行了复制,将方法签名改为byte[].

第三次,又要求我们对char[]数组进行排序,这个时候我们就不得不停下来思考了,以上两种需求,除了方法签名不一样以为,其他的都一模一样。所以我们引进了泛型的概念,将int[]、byte[]、char[]使用T[]来表示,T代表type,指代任何类型。所以我们又得到了泛型类的概念。

public class SortHelper<T> { public void BubbleSort(T[] array){ // 方法实现体 } }

这样,当我们需要对int[]进行排序时,我们可以这样声明:

SortHelper<int> sorter = new SortHelper<int>(); int[] array = { 8, 1, 4, 7, 3 }; sorter.BubbleSort(array);

当我们需要对char[]进行排序时,我们就能这样声明:

SortHelper<char> sorter = new SortHelper<char>(); char [] array = { 8, 1, 4, 7, 3 }; sorter.BubbleSort(array);

再也不用重复的对代码进行复制,然后修改方法签名了。

结论:通过使用泛型,极大的减少了重复代码,使程序更加清爽。泛型类可以让我们在需要时传入任何类型,在.net中,我们称作类型参数。

3.类型参数约束

我们定义了一个Book类,对它实现排序,该怎么实现呢?假设该类包含两个字段,一个int类型的单价price,一个string类型的title标题。

Book[] bookArray = new Book[2]; Book book1 = new Book(30, "HTML5解析"); Book book2 = new Book(21, "JavaScript实战"); bookArray[0] = book1; bookArray[1] = book2; SortHelper<Book> sorter = new SortHelper<Book>(); sorter.BubbleSort(bookArray); foreach (Book b in bookArray) { Console.WriteLine("Price:{0}", b.Price); Console.WriteLine("Title:{0}\n", b.Title); }

那么到底该怎么进行比较大小呢? 是以价格为准呢,还是以书名的字母顺序呢?都不好说,所以这个时候就需要定义一个比较规则了,那么在.net中,实现比较的基本方法是实现IComparable接口。此接口有泛型和非泛型两个。

public class Book :IComparable { // CODE:上面的实现略 public int CompareTo(object obj) { Book book2 = (Book)obj; returnthis.Price.CompareTo(book2.Price); } }

这里我们以price为准来进行排序,可以看到CompareTo()方法参数接受了一个object类型的参数,我们却违背了Liskov替换原则。原则要求方法内部不应该对方法所接受的参数进行向下的强制转换。我们都知道,在C#中,object是一切类型的基类。book类继承自Object类,所以我们在将object转换为book进行价格比较时,就称作向下的强制转换.

泛型类,所接受的T类型参数必须能够进行比较--即实现IComparable接口,所以我们可以这样定义:

public class SortHelper<T> where T:IComparable { // CODE:实现略 }

4.泛型方法

既然有了泛型类,我们就引入了泛型方法的概念,泛型方法的引入主要是为了解决,我们在声明泛型类时,避免因为调用某一个方法不得不将类型参数T传给某个类,使得那些不需要调用该方法的情况下,创建一个类实例也需要传递类型参数的情况。

如下:SpeedSort()就是一个泛型方法

public class SortHelper { public void SpeedSort<T>(T[] Array) where T:IComparable { } } 二.泛型和集合类型

1.避免隐式的装箱拆箱

典型的非泛型集合ArrayList,它包容了任何类型, 所以它接受的参数为所有类型的基类Object, 当我们需要获取到一个int[],需要循环遍历ArrayList,并将它一一添加到我们所声明的数组集合中去,由于object是一个引用类型,而int是一个值类型,这样在得到这么一个包含int类型的ArrayList数组时,我们就需要不断的进行装箱、拆箱的操作,这对.net来说是相对耗时的。

通过使用泛型,由于集合中的元素类型在编译时就已确定,避免了装箱和拆箱的操作,很显著的提高集合类型的性能。 在.NET中,与ArrayList作用等同的泛型类型是 List.

2.编译时的类型安全

由于使用泛型,集合中的元素在编译时就已确定,所以当我们想将一个int类型的数值转换为string时,编译器会直接告诉我们编译错误,这种在编译时就检查出的错误,叫做编译时错误,与之相对的,就是我们的运行时错误,即当使用ArrayList时,因为它所接受的参数是object基类,编译器视为将一个int类型的数值转换为string时是正常的,只有运行时才检查出错误。

三.小结

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwypf.html