很多时候须要确保添加到泛型表中的元素满足一定的约束(比如,从给定的基类派生,或者实现一个特定的接口)。
public class Employee:IComparable<Employee>
{
private string name;
public Employee(string name)
{
this.name = name;
}
public override string ToString()
{
return this.name;
}
#region IComparable<Employee> 成员
public int CompareTo(Employee rhs) //如果直接继承IComparable的话,那么Employee对应的是Object
{
return this.name.CompareTo(rhs.name);
}
#endregion
public bool Equals(Employee rhs)
{
return this.name == rhs.name;
}
}
//结点必须实现T的Node的IComparable
//使用where关键字
//约束Node只能接受实现了IComparable接口的项
public class Node<T>:IComparable<Node<T>> where T:IComparable<T>
{
//成员字段
private T data;
private Node<T> next = null;
private Node<T> prev = null;
//构造方法
public Node(T data)
{
this.data = data;
}
//属性
public T Data
{
get
{
return this.data;
}
}
public Node<T> Next
{
get { return this.next; }
}
#region IComparable<Node<T>> 成员
public int CompareTo(Node<T> rhs)
{
//因为存在约束所以可行
return data.CompareTo(rhs.data);
}
#endregion
public bool Equals(Node<T> rhs)
{
return this.data.Equals(rhs.data);
}
//方法
public Node<T> Add(Node<T> newNode)
{
if (this.CompareTo(newNode) > 0) //在我之前
{
newNode.next = this; //新结点指向我
//如果前面有结点,将它设为指向
//新结点,作为后继
if (this.prev != null)
{
this.prev.next = newNode;
newNode.prev = this.prev;
}
//将当前结点的prev指向新结点
this.prev = newNode;
//返回newNode,如果它是新的头结点
return newNode;
}
else //在我之后
{
//如果后面有结点,新结点一起传递,一共比较
if (this.next != null)
{
this.next.Add(newNode);
}
else //没有后续结点了,所以将新结点设为后续结点,将其prev设为指向我
{
this.next = newNode;
newNode.prev = this;
}
return this;
}
}
public override string ToString()
{
string output = data.ToString();
if (next != null)
{
output += ", " + next.ToString();
}
return output;
}
}
public class LinkedList<T> where T:IComparable<T>
{
//成员字段
private Node<T> headNode = null;
//索引器
public T this[int index]
{
get
{
int ctr = 0;
Node<T> node = headNode;
while (node != null && ctr <= index)
{
if (ctr == index)
{
return node.Data;
}
else
{
node = node.Next;
}
++ctr;
}
throw new ArgumentOutOfRangeException();
}
}
public LinkedList()
{
}
//方法
public void Add(T data)
{
if (headNode == null)
{
headNode = new Node<T>(data);
}
else
{
headNode = headNode.Add(new Node<T>(data));
}
}
public override string ToString()
{
if (this.headNode != null)
{
return this.headNode.ToString();
}
else
{
return string.Empty;
}
}
}
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
public void Run()
{
LinkedList<int> myLinkedList = new LinkedList<int>();
Random rand = new Random();
Console.Write("Adding: ");
for (int i = 0; i < 10; i++)
{
int nextInt = rand.Next(10);
Console.Write("{0} ", nextInt);
myLinkedList.Add(nextInt);
}
LinkedList<Employee> employees = new LinkedList<Employee>();
employees.Add(new Employee("Douglas"));
employees.Add(new Employee("Paul"));
employees.Add(new Employee("George"));
employees.Add(new Employee("Ringo"));
Console.WriteLine("\nRetrieving collections...");
Console.WriteLine("Integers: " + myLinkedList);
Console.WriteLine("Employees: " + employees);
}
}
这个例子中,一开始就声明了一个能够插入链表的类:
public Class Employee:IComparable<Employee>
这个声明表明,Employee对象是可以进行比较的,可以看到Employee类实现了必需的方法(CompareTo和Equals)。请注意,这些方法都是类型安全的(它们知道传给自己的参数将是Employee类型的)。LinkedList本身声明为只能保存实现了IComparable的类型:
public Class LinkedList<T> where T:IComparable<T>
因此,可以保证能够对链表进行排序。LinkedList保存了一个Node类型的对象。Node也实现了IComparable,而且要求它的数据成员也要实现IComparable:
public class Node<T>:IComparable<Node<T>> where T:IComparable<T>
这些约束使得Node的CompareTo方法的实现既简单又安全,因为Node知道将与数据可以比较的其他Node进行比较:
public int CompareTo(Node<T> rhs)
{
//因为存在约束所以可行
return data.CompareTo(rhs.data);
}
请注意,我们无需测试rhs是否实现了IComparable,我们已经约束Node只保存实现了IComparable的数据。