hi,you guys。
今天我们继续学习<叩响c#之门>,今天我们学习的内容是集合与泛型。集合、泛型是我们项目开发中经常会用的知识。学好泛型、集合,对我们开发工作有很大的帮助。
集合
物以类聚,相同的东西需要归于一类。我们常常将相互关联的对象组成集合,自然数组成自然数集。同班同学组成班级,诗人做的诗篇,组成诗集。集合中的对象,称为元素(Element)。C#为我们提供一组功能强大的集合类,实现了多种不同类型的集合,我们可以根据实际用途选择恰当的集合类型。下表,是FCL(Framework Common Library)类库为我们提供的部分集合类。
QQ Photo20140823155454" src="/Upload/Images/2014082318/6AD16326078E244F.jpg" alt="QQ Photo20140823155454" width="1028" height="193" border="0" />
除了Array在System命名空间下,其余的类都位于System.Collections命名空间下。这些类通过直接或间接的继承一些接口,来实现其自身强大的功能。我们之前在项目中用过foreach循环语句,遍历一个集合或数据集。那么是如何foreach是如何实现对集合或数据集的遍历的呢?(与其说是遍历,不如说是迭代。关于迭代概念,大家可以参考一些数据结构书籍的递归算法)。原来FCL提供的集合类,都直接或间接的实现了IEnumerable接口,这个接口声明了一个名为GetIEnumerator()方法。这个方法返回一个继承了IEnumerator接口的类,我们通常将这个类称为迭代器。
//IEnumerable接口 public interface IEnumerable { IEnumerator GetIEnumerator(); }
IEnumerable接口类
//IEnumerator接口 public interface IEnumerator { bool MoveNext(); //获取下一个元素 object Current{get;} //获取当前元素 void Reset(); //将枚举数设置为其初始位置 }
IEnumerator接口类
foreach语句就是通过访问迭代器来获取集合中的元素。ICollection接口也是一个很基础的接口,它继承了IEnumerable接口,并且添加了一个Copy()方法,和一个Count属性以及两个用于同步的属性。
//ICollection接口 public interface ICollection:IEnumerable { void Copy(System.Array array,int index); //复制到数组 int Count{get;} //元素个数 bool IsSynchronized; //是否同步 object SyncRoot{get;} //用于同步的对象 }
IList接口、IDictionary接口都继承于ICollection接口。
关于各个集合类的一些方法,大家可以下去自己练习一下。因为,本章主要讲解的是泛型类。其实,在项目中大家更多的会去使用泛型,因为集合存在一个弊端。
集合类的弊端
大家看看下面的代码:
ArrayList list=new ArrayList(); lsit.Add(10); //添加元素 int n=(int)lsit[0]; //取出元素
因为所有类型都继承于object的类型,所以当我们调用.Add()方法,向集合中添加元素时,系统会默认为object类型。此时,如果添加的元素不是引用类型而是值类型,那么在向集合添加元素时,就会进行装箱操作,将值类型转换为引用类型。同样,在我们读取元素时,需要拆箱操作,将object的类型转换为值类型。这样做,会有三个缺点:
第一、在装箱、拆箱的过程中,可能会造成一定的性能损失。
第二、什么类型的数据都往集合中放,不利于编译器进行严格的类型安全检查。
第三、显示转换类型,降低了程序的可读性。Note(现在计算机越来越快,性能也不是唯一目标了。软件开发成本在于软件维护与升级。所以,提高代码可读性可以降低软件开发成本呢。)
ArrayList list=new ArrayList(); list.Add(10); list.Add("hello"); foreach(int element in list) { int n=(int)element; }
上面这段代码,编译不会出错。运行会出现,因为”hello”不能转换为int类型。现在大家看出集合类的弊端了吧,那么泛型类又有什么地方强于集合呢?其实不难想象,泛型强于集合的地方,一定是集合比较薄弱的地方。集合薄弱的地方就在,集合类的元素类型没有限制。
泛型
泛型与集合的功能基本一致,唯一的不同点在于,泛型类的元素类型受我们控制,是我们指定的类型,而不是万物之祖的object类型。泛型具有一个参数列表<T>,在整个类里用T代表元素类型,T的类型是不确定的,是抽象类型。在我们实例化类时,将抽象类型的元素具体化,具体类型的参数将代替T。看程序:
// 泛型类 public class Generic<T> { public void Check() { Console.WriteLine(this.GetType()); //输出T的类型 } } //实例化泛型类 Generic<int> instanceInt=new Generic<int>(); instanceInt.Check(); //输出的类型为System.Int32 Generic<String> instanceString=new Generic<String>(); instanceString.Check(); //输出的类型为System.String;
泛型类中的T,是抽象类型。实例化时,才会将其具体化。例如上面的instanceInt,就是将泛型类中的T,具体化为Int类型。instanceString,就泛型类的T具体化为String类型.我们可以定义泛型类,同意也可定义泛型方法,泛型接口等。看下面的代码:
//泛型类 public static void Swap<T>(ref T a,ref T b) { T t=a; a=b; b=t; }
此时的a,b都是抽象的,都是未知的类型。
Static void Main(string[] args) { int x=100; int y=200; Swap<int> (ref x,ref y); Console.WriteLine("x={0},y={1}",x,y); }
我们在调用泛型方法时,将参数具体化了。
C#为我们提供了一些泛型类:
List<T>
Stack<T>
Queue<T>
SortedList<TKey,TValue>
Dictionary<TKey,TValue>
关于他们的一些方法,大家可以查看相关手册。学会通过查看手册来学习编程,是很重的。好了今天的泛型、集合就到这里了。最后,我把作者讲的一句话,给大家分享一下。“实践中磨练编程技能,思考中感悟编程本质”。