泛型概念:类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法的时候。例如,通过使用泛型类型参数T,可以编写其他客户端代码能够使用的单个类,而不致引入运行时强制转换或装箱操作的成本或风险。
(一)泛型约束
如果要检查泛型列表中的某个项以确定它是否有效,或者将它与其他某个项进行比较,则编译器必须在一定程度上保证它需要调用的运算符或方法将受到客户端代码可能指定的任何类型参数的支持。这种保证是通过对泛型类定义应用一个或多个约束获得的。例如,基类约束告诉编译器:仅此类型的对象或从此类型派生的对象才可用作类型参数。一旦编译器有了这个保证,它就能够允许在泛型类中调用该类型的方法。约束是使用上下文关键字where应用的。
class Student { private string name; private int id; public Student(string s, int i) { name = s; id = i; } public string Name { get { return name; } set { name = value; } } public int ID { get { return id; } set { id = value; } } } public class GenericList<T> where T : Student { private class Node { private Node next; private T data; public Node(T t) { next = null; data = t; } public Node Next { get { return next; } set { next = value; } } public T Data //此下T相当于Student类型 { get { return data; } set { data = value; } } } private Node head; public GenericList() //constructor { head = null; } public void AddHead(T t) { Node n = new Node(t); n.Next = head; head = n; } public IEnumerator<T> GetEnumerator() { Node current = head; while (current != null) { yield return current.Data; current = current.Next; } } public T FindFirstOccurrence(string s) { Node current = head; T t = null; while (current != null) { //The constraint enables access to the Name property. if (current.Data.Name == s) //此处可以直接使用Student类中的字段Name. { t = current.Data; break; } else { current = current.Next; } } return t; } }
调用如下:此时如果不用Student类作为参数传将会导致编译错误,这样有利于保证程序在运行时的类型安全。
(一)泛型类和方法
1.1 default关键字
在泛型类和泛型方法中产生的一个问题是,在预先未知以下情况时,如何将默认值分配给参数化类型T,T是引用类型还是值类型。如果T为值类型,则它是数值还是结构。
给定参数化类型T的一个变量t,
① 当T为引用类型时:t=null 有效
② 当T为数值类型而不为结构体时:t=0有效
解决方案是使用 default 关键字,此关键字对于引用类型会返回null,对于数值类型会返回零。对于结构,此关键字将返回初始化为零或 null 的每个结构成员,具体取决于这些结构是值类型还是引用类型。
1.2 类型参数T的创建
代码①和②处表明了两种创建泛型参数T的两种方式。
(二)父子类的泛型方法