集合与泛型

  • 格式:doc
  • 大小:102.50 KB
  • 文档页数:21

第2章集合与泛型2.1 集合概述所谓集合是特殊元素们的一种聚合。

集合的元素被称为是成员。

集合有两个最重要的属性,一个是集合成员都是无序的,另一个则是集合的成员不会出现超过一次。

在计算机科学领域内集合扮演着非常重要的角色,但是不把集合包含作为C#语言的一种数据结构。

2.1.1 集合的定义人们把集合定义成相关成员的无序聚集,而且集合中的成员不会出现超过一次。

集合书写成用一对闭合大括号包裹成员列表的形式,例如{0,1,2,3,4,5,6,7,8,9}。

只要全部成员只书写一次,就可以按照任意顺序书写集合,所以此前的集合实例还可以写成{9,8,7,6,5,4,3,2,1,0}或其他任意成员组合的形式。

为了使用集合需要知道一些有关集合的定义。

1. 不包含任何成员的集合称为空集合。

全域是所有可能成员的集合。

2. 如果两个集合包含完全一样的成员,那么就认为这两个集合相等。

3. 如果第一个集合的全部成员都包含在第二个集合内,就认为第一个集合是第二个集合的子集。

2.1.2 集合的操作下面描述了在集合上执行的基本操作。

1. 联合:由第一个集合中的所有成员和第二个集合中不包含在第一个集合的成员组成的新集合。

2. 交叉:由既属于第一个集合又属于第二个集合的成员组成的新集合。

3. 差异:由属于第一个集合但不属于第二个集合的成员组成的新集合。

2.2 集合类ArrayList是与数组相当的集合类。

还有其他类型的集合:队列、栈、有序表和哈希表,如下所示:●ArrayList 动态数组●Queue 队列●Stack 栈●BitArray 位数组●Hashtable 散列表●SortedList 有序表集合类位于System.Collections命名空间,集合类可以组合为集合,存储Object类型的元素。

2.3 集合的一种实现HashTable类是.NET框架类库中较为有效的数据结构之一,它的存取速度较其它类而2.1 泛型概述泛型(Generic Type)是.NET Framework 2.0的一大特性。

泛型的主要思想就是将算法与数据结构完全分离开来,使得一次定义的算法能够作用于多种数据结构,从而实现高度可重用的开发。

通过泛型可以定义类型安全的数据结构,而没有必要使用实际的数据类型。

这将显著提高性能并得到更高质量的代码,因为可以重用数据处理算法,而没有必要复制类型特定的代码。

泛型是一个很强大的特性,对于集合类而言尤其如此。

.NET 1.1中的大多数集合类都基于Object类型。

.NET 从2.0开始提供了实现为泛型的新集合类。

泛型不仅限于类,还可用于委托、接口和方法的泛型。

在.NET 2.0之前,不存在泛型,在开发通用容器时,需要通用容器能存储各种类型的实例。

在.NET Framework 1.1下,必须使用基于object类型的系统集合类(例如ArrayList,Stack,Queen等),但由于集合类中的项都是Object类型的,因此每次使用时都必须进行装箱拆箱操作,不仅大大降低了程序的性能,而且存在类型安全问题(Object类在编译期间没有类型安全性)。

泛型(Generic Type)的出现较好的解决了上述问题,通过它,可以轻松创建指定类型的集合。

泛型集合类不仅是类型安全的,而且使用时不需要进行烦琐的装箱拆箱操作。

泛型是C# 2.0中的新增元素(类似于C++中模板)。

这种机制允许将类名作为参数传递给泛型类型,并生成相应的对象。

主要利用System.Collections.Generic命名空间下面的List 泛型类来创建集合。

语法如下:List<T> ListOfT = new List<T>( );其中的"T"就是所要使用的类型,既可以是简单类型,如string、int,也可以是用户自定义类型。

运行结果如下图:下面介绍泛型的优点:1. 性能泛型的一个主要优点是性能。

对值类型使用System.Collections命名空间的集合类,存储数据时需要把值类型转换为引用类型,获取数据时需要把引用类型转换为值类型,即需要进行装箱和拆箱操作。

例如,下面例子在存取数据时就进行了装箱拆箱操作。

System.Collections.Generic命名空间中的List<T>类不使用对象,而是在使用时定义类型。

在下面的例子中,List<T>类的泛型类型定义为int,所以int类型在JIT编译器动态生成的类中使用,不再进行装箱和拆箱操作:2. 类型安全泛型的另一个特性是类型安全。

与ArrayList类一样,如果使用对象,可以在这个集合中添加任意类型。

下面的例子在ArrayList类型的集合中添加一个整数、一个字符串和一个如果这个集合使用下面的foreach语句迭代,而该foreach语句使用整数元素来迭代,编译器就会编译这段代码。

但并不是集合中的所有元素都可以转换为int,所以会出现一个运行异常:错误应尽早发现。

在泛型类List<T>中,泛型类型T定义了允许使用的类型。

有了List<int>的定义,就只能把整数类型添加到集合中。

编译器不会编译这段代码,因为Add()方法的参数无效:3. 代码重用泛型允许更好地重用代码。

泛型类可以定义一次,用许多不同的类型实例化。

例如,System.Collections.Generic命名空间中的List<T>类用一个int、一个字符串和一个MyClass类型实例化:泛型类型可以在一种语言中定义,在另一种.NET语言中使用。

2.2 创建泛型类泛型最显著的一点就是它参数化了类型,把类型作为参数抽象出来,从而使我们在实际的运用当中能够更好的实现代码的重复利用,同时它提供了更强的类型安全,更高的效率,不过在约束方面,它只支持显式的约束,这样在灵活性方面就显得不是那么好了。

泛型之所以能够提供更高的效率是因为泛型在实例化的时候采用了"on-demand"的模式,即按需实例化,发生在JIT(Just In Time)编译时。

下面来看如何定义一个泛型类,很简单,你只需要意识到一点——类型在这里被参数化了:使用泛型类Collection<T>,相当于定义了一个类模板,在具体使用时,需要什么类型即可将它实例化为什么类型,从而实现了代码重用。

由于可以用任何类型实例化它,且无需装箱操作,因此比基于Object的非泛型方式获取了更高的性能。

如果将Collection<T>实例化为int类型,则使用Add ()方法传送非int值,就会出现一个编译错误,所以说它是类型安全的。

使用泛型IEnumerable<T>,foreach语句也是类型安全的,如果foreach语句中的变量不是int,也会出现一个编译错误。

2.3 泛型类的特性在创建泛型类时,需要一些其他C#关键字。

例如,不能把null赋予泛型类型。

此时,可以使用default关键字。

如果泛型类型不需要Object类的功能,但需要调用泛型类上的某些特定方法,就可以定义约束。

1. 默认值在创建泛型类时,如果需要给类型T指定null,但是,不能把null赋予泛型类型。

原因是泛型类型也可以实例化为值类型,而null只能用于引用类型。

为了解决这个问题,可以使用default关键字。

通过default关键字,将null赋予引用类型,将0赋予值类型。

default关键字根据上下文可以有多种含义。

switch语句使用default定义默认情况。

在泛型中,根据泛型类型是引用类型还是值类型,default关键字用于将泛型类型初始化为null 或0。

2. 约束C#中的泛型只支持显式的约束,因为这样才能保证C#所要求的类型安全,但显式的约束并非时必须的,如果不加约束,泛型类型参数将只能访问System.Object类型中的公有方法。

“显式约束”由where子句表达,可以指定“基类约束”,“接口约束”,“构造器约束”,“值类型/引用类型约束”共四种约束。

提示:在C#中,where子句的一个重要限制是,不能定义必须由泛型类型执行的运算符。

运算符不能在接口中定义。

在where子句中,只能定义基类、接口和默认构造函数。

3. 继承如何实现泛型类的继承呢?这里需要满足下面两点中的任何一点即可:1、泛型类继承中,父类的类型参数已被实例化,这种情况下子类不一定必须是泛型类;2、父类的类型参数没有被实例化,但来源于子类,也就是说父类和子类都是泛型类,并且二者有相同的类型参数;//如果这样写的话,显然会报找不到类型T的错误class SubItem : Item<T> { }//正确的写法应该是class SubItem : Item <string>{ }class SubItem <T> : Item<string> { }class SubItem <T> : Item<T> { }4. 静态成员泛型类的静态成员只能在类的一个实例中共享。

下面看一个例子。

2.4 泛型接口2.5 泛型方法我们再来看泛型方法,C#的泛型机制只支持在方法声明上包含类型参数,也即是泛型方法。

特别注意的是,泛型不支持在除了方法以外的其他类/接口成员上使用类型参数,但这些成员可以被包含在泛型类型中,并且可以使用泛型类型的类型参数。

还有一点需要说的就是,泛型方法可以在泛型类型中,也可以存在于非泛型类型中。

下面通过例子看一下2.6 泛型委托再来看一下泛型委托,泛型委托支持在返回值和参数上应用类型参数,下面例子中定义了一个类型参数为T的委托,然后在类中利用委托调用方法:2.7 泛型集合类在CLR 2.0之前,不存在泛型。

现在泛型集合类通常是集合的首选类型。

泛型集合类是类型安全的,如果使用值类型,是不需要装箱操作的。

如果要在集合中添加不同类型的对象,且这些对象不是相互派生的,例如在集合中添加int和string对象,就只需基于对象的集合类。

另一组集合类是专用于特定类型的集合,例如StringCollection类专用于string 类型。

对象类型的集合类位于System.Collections命名空间;泛型集合类位于System.Collections. Generic命名空间;专用于特定类型的集合类位于System.Collections.Specialized命名空间。

以下是System.Collections. Generic命名空间下的泛型集合类:●List<T> 列表●Queue<T> 队列●Stack<T> 栈●LinkedList<T> 链表●HashSet<T> 集●Dictionary<TKey, TValue> 字典●SortedDictionary<TKey, TValue>●SortedList<TKey, TValue> 有序表●Lookup<TKey, TElement>习题与练习一、什么是泛型?泛型有那些优点?二、创建自己的泛型集合类,要求实现System.Collections.Generic命名空间下的List 泛型类的核心功能。