泛型是2.0版C#语言和公共语言运行库(CLR)中的一个新功能,它将类型参数的概念引入.NET Framework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法时。例如,通过使用泛型类型参数T,可以编写其他客户端代码能够使用的单个类,而不致引入运行时强制转换或装箱操作的成本或风险,避免进行强制类型转换的需求提高类型安全性。这样开发人员可以更轻松地创建泛化的类和方法。本节将对泛型及其应用进行详细讲解。
1 泛型概述及优点
泛型类和泛型方法同时具备可重用性、类型安全和效率高等特点,它通常用在集合和在集合上运行的方法中。.NET 2.0版类库提供一个新的名为System.Collections.Generic的命名空间,其中包含几个新的基于泛型的集合类。建议面向2.0版的所有应用程序都尝试使用新的泛型集合类。
同样,也可以创建自定义泛型类型和方法,以提供个人的通用解决方案和设计类型安全的高效模式等。
泛型类和方法接受“类型参数”,它们指定了要操作的对象的类型。例如:
public class Test<T>
{
}
在实例化时才指定类型。例如:
Test<int> tree = new Test<int>();
使用泛型类型有以下优点:
l 使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能;
l 使用泛型可以创建集合类;
l .NET Framework类库在System.Collections.Generic命名空间中包含几个新的泛型集合类,应尽可能地使用这些类来代替普通的类,如System.Collections命名空间中的 ArrayList;
l 可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托;
l 可以对泛型类进行约束以访问特定数据类型的方法;
l 关于泛型数据类型中使用的类型的信息可在运行时通过反射获取。
2 泛型中的类型参数T
类型参数T用来定义泛型类时的占位符,T并不是一种类型,它仅代表了某种可能的类型。在定义时,T出现的位置可以在使用时用任何类型来代替。
例如:
//定义一个泛型类
public class GenericArry<T>
{
void Add(T input) { }
}
class TestGenericArry
{
//自定义一个类型
private class ExampleClass { }
static void Main()
{
// 实例化一个整型的GenericArry
GenericArry<int> list1 = new GenericArry<int>();
//实例化一个字符串型的GenericArry
GenericArry<string> list2 = new GenericArry<string>();
//实例化一个自定义类型的GenericArry
GenericArry<ExampleClass> list3 = new GenericArry<ExampleClass>();
}
}
3 泛型的使用
ch0509实例位置:mr\05\sl\Ex05_09
下面通过实例来介绍如何在程序中定义和使用泛型。
程序开发步骤如下。
(1)启动Visual Studio 2005,新建一个控制台应用程序,命名为Ex05_09。
(2)在自动生成的Program.cs文件中编写如下代码:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Ex05_09
{
// 尖括号中的类型参数T
public class MyList<T> : IEnumerable<T>
{
protected Node head;
protected Node current = null;
//嵌套类型也是T上的泛型
protected class Node
{
public Node next;
// T作为私有成员数据类型
private T data;
// 在非泛型构造函数中使用的T
public Node(T t)
{
next = null;
data = t;
}
public Node Next
{
get { return next; }
set { next = value; }
}
// T作为属性的返回类型
public T Data
{
get { return data; }
set { data = value; }
}
}
public MyList()
{
head = null;
}
// T作为方法参数类型
public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
}
// 实现GetEnumerator以返回IEnumerator<T>,从而启用列表的
// foreach迭代。请注意,在C# 2.0 中,不需要实现Current和MoveNext,
// 编译器将创建实现 IEnumerator<T> 的类
public IEnumerator<T> GetEnumerator()
{
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
// 必须实现此方法,因为IEnumerable<T>继承IEnumerable
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class SortedList<T> : MyList<T> where T : IComparable<T>
{
// 一个未优化的简单排序算法,
// 该算法从低到高对列表元素排序
public void BubbleSort()
{
if (null == head || null == head.Next)
return;
bool swapped;
do
{
Node previous = null;
Node current = head;
swapped = false;
while (current.next != null)
{
// 由于需要调用此方法,因此,SortedList
// 类在 IEnumerable<T> 上是受约束的
if (current.Data.CompareTo(current.next.Data) > 0)
{
Node tmp = current.next;
current.next = current.next.next;
tmp.next = current;
if (previous == null)
{
head = tmp;
}
else
{
previous.next = tmp;
}
previous = tmp;
swapped = true;
}
else
{
previous = current;
current = current.next;
}
}// 结束 while
} while (swapped);
}
}
// 一个将自身作为类型参数来实现IComparable<T>的简单类,
// 是对象中的常用设计模式,这些对象存储在泛型列表中
public class Person : IComparable<Person>
{
string name;
int age;
public Person(string s, int i)
{
name = s;
age = i;
}
// 这会使列表元素按age值排序
public int CompareTo(Person p)
{
return age - p.age;
}
public override string ToString()
{
return name + ":" + age;
}
//必须实现Equals
public bool Equals(Person p)
{
return (this.age == p.age);
}
}
class Program
{
static void Main(string[] args)
{
// 声明并实例化一个新的范型SortedList类,Person是类型参数
SortedList<Person> list = new SortedList<Person>();
// 创建name和age值以初始化Person对象
string[] names = new string[] { "明日", "科技", "明日科技", "吉林省明日科技", "吉林", "山西", "辽宁", "黑龙江"};
int[] ages = new int[] { 30, 36, 44, 50, 16, 10, 18, 24};
// 填充列表
for (int x = 0; x < names.Length; x++)
{
list.AddHead(new Person(names[x], ages[x]));
}
Console.WriteLine("未排序列表:");
// 打印出未排序的列表
foreach (Person p in list)
{
Console.WriteLine(p.ToString());
}
// 对列表进行排序
list.BubbleSort();
Console.WriteLine(String.Format("{0}排序列表:", Environment.NewLine));
// 打印出排序的列表
foreach (Person p in list)
{
Console.WriteLine(p.ToString());
}
}
}
}
实例运行结果如图5.8所示。
图5.8 泛型的使用